原文链接 : http://blogs.msdn.com/salvapatuel/archive/2009/06/08/working-with-memory-mapped-files-in-net-4.aspx

预备知识 : 本文需要你对 OS 内存管理有一定了解。

我想探索下即将到来的 .NET 4 中一些与众不同的新特性,而不是已被大众所熟知的动态类型、协变与逆变等特性。出于对性能增强的喜爱,接下来俺将发表几篇新特性的博文。

内存映射文件对于托管世界的开发人员来说,似乎就像是火星人一样陌生(画外音 : 还是回火星吧,地球上很危险嘀)。但是它确实已经行之经年,毫不客气的说,它在 OS 中的地位相当重要。实际上,任何想要共享数据的通信模型都会在幕后使用它。

那么内存映射文件究竟是个什么玩意呢?内存映射文件允许你保留一块地址空间,然后提交物理存储到这块空间(嗯,听起来是不是很像虚拟内存?)。这哥俩最主要的区别就在于物理存储来自于磁盘上已有的文件,而不是内存管理器。这样做有两大意图 :

1.访问磁盘文件上的数据不需要执行文件 I/O 操作和缓存文件内容。当你访问超大型文件数据时,作用尤其显著。 2.你能使用内存映射文件让运行在同一台机器上的多个进程共享彼此数据。

译注 : Windows 操作系统自身就使用内存映射来执行 DLL,并装载和执行 EXE 文件。

内存映射文件是单一机器多进程间数据通信的最高效的方式。此外,如果你参考其他 IPC 方法,就会看到如下图所示的架构 :

Woo…,现在你对该技术的强大威力有个大概印象了吧(在 System.IO 命名空间下,它甚至可以完全替代 P/Invoke 技术)。

现在,让我来快速解释下它如何工作。我们有两种内存映射文件模型。一个呢,就是使用自定义文件。它可以是应用程序想要访问的任意文件。另一个呢,则是页面文件。我们将和内存管理器一块共享它(这是最常用的技术模型)。

先来介绍下自定义文件模型。首先我们要做的事就是为我们要使用的文件创建一个 FileStream,它可以是已有的文件或者新文件(记住,你应该以共享方式打开这个文件,否则其他进程就无法访问它)。创建合适的流之后,现在就可以创建内存映射文件了。如下所示 :

1: using System.IO.MemoryMappedFiles;1: MemoryMappedFile memoryMappedFile = MemoryMappedFile.CreateFromFile(2: new FileStream(@"E:\Temp\Map.mp", FileMode.Create), //Any stream will do it3: "MyMemoryMappedFile", //Name4: 1024 * 1024, //Size in bytes5: MemoryMappedFileAccess.ReadWrite); //Access type

这里,我使用了 MemoryMappedFile 类的一个特简单的构造函数。我们定义了要用到的流,然后给内存映射文件起了个名字。此外,我们还需要知道内存映射文件的大小(按字节计)和访问的类型。这样,我们就创建了一个内存映射文件。但是在开始使用它之前,我们还需要一个映射视图。接下来,我们就来创建它 :

MemoryMappedViewAccessor FileMapView = memoryMappedFile.CreateViewAccessor();

这个映射覆盖了整个文件。如果我们现在就要从内存映射文件读或写信息,只需要调用带有正确偏移量的映射视图方法就行了。

int number = 1234;FileMapView.Write(0, number);FileMapView.Write<Container>(4, ref container);

我们可以往任何内置类型或带有泛型约束的自定义类型写入数据。内存映射文件有个很好的特性就是持久性。在你关闭它之前,里面的内容都会堆积在磁盘上。这对于应用程序间共享缓存信息非常有用。

Well,其它进程如何读取该内存映射文件的内容呢。一样,我们先创建一个内存映射文件。不过我们用的是另外的构造函数,以打开已有的内存映射文件。如果不存在,再新建也不迟。译注 : 原文中的代码示例是错误的。

MemoryMappedFile MemoryMapped = MemoryMappedFile.CreateOrOpen("MyMemoryMappedFile", 1024 * 1024, MemoryMappedFileAccess.ReadWrite);

接下来创建映射视图来读取信息,如下所示 :

using (MemoryMappedViewAccessor FileMap = memoryMappedFile.CreateViewAccessor()){Container newContainer = new Container(); FileMap.Read<Container>(4, out newContainer);}

看,是不是很简单?但是这种方法有个小小的缺点,这和内存映射文件的大小有关。如果事先不知道大小的话,为了以防万一,你可能会构造一个超级大的文件。可是这样就浪费了大量的地址空间。毕竟你保留的地址远比你提交的物理空间要大,不是吗?

为了解决这个问题,我们可以使用页面文件。这对于百忙中提交数据非常有利。但同时也引入了一个新问题 : 你不会拥有自己的文件,而且映射会一直持续到最后的句柄销毁之后。不过仔细想想,这种方案挺合理的。

现在我们重新构造下前面的示例。这次,我将使用最完整参数的构造函数,这样还可以介绍一些其他的特性。当然,这些特性同样适用于自定义文件。

MemoryMappedFileSecurity customSecurity = new MemoryMappedFileSecurity();MemoryMappedFile pagedMemoryMapped = MemoryMappedFile.CreateNew(@"Salvador", //Name1024*1024, //SizeMemoryMappedFileAccess.ReadWrite, //Access typeMemoryMappedFileOptions.DelayAllocatePages, //Pseudo reserve/commitcustomSecurity, //You can customize the securityHandleInheritability.Inheritable //Inherit to child process);

MemoryMappedFileSecurity 类允许你自定义哪个进程可以访问资源。当你想要保护敏感信息时,或者你不想其他进程改变此内存映射文件时,这个特性非常有用。你可以查看这个对象所有你想要改变的不同设置。在这里你可以获得更详细的信息。如果我们想要探究内存映射文件结构的话,不需要构造一个流,只要找到该资源的名字即可。这会把映射名称和基于文件大小的区域链接起来。如此多个进程间就知道如何访问文件了。注意,使用 DelayAllocatePages 属性后,只有在必要的时候才会预留/提交地址空间。最后一个有意思的参数就是句柄继承模型了。它允许在必要的时候,可以喝子进程共享资源。

如何访问文件就跟前述的示例一样了。千万记住,如果你关闭了内存映射文件,那么它就不能访问了。这个问题困扰了很多开发人员。

最后,让我们来看一下另外一个有意思的领域 : 创建多个映射视图。它们同时工作访问同一个内存映射文件的不同区域。这个时候你就得适当保护内容和同步访问。

我们可以定义不同的偏移量和长度来创建自己的映射视图。如下所示 :

MemoryMappedViewAccessor writeMapView = memoryMappedFile.CreateViewAccessor(0, 1024,MemoryMappedFileAccess.ReadWrite);MemoryMappedViewAccessor readMapView = memoryMappedFile.CreateViewAccessor(1025, 1024,MemoryMappedFileAccess.Read);

现在你可以享受 .NET 4.0 所带来的高性能数据共享模型的强大威力了。注意,本文基于 .NET 4.0 BETA1 创作。

译注 : UNIX 没有使用映射文件来实现内存共享,它有显式的内存共享 API 函数。这些函数式 shmget、shmctl、shmat、shmdt,以及 mmap、munmap。最后两个函数虽然跟本文所讲的有点类似,但是它们没有映射对象。

[译].NET 4 中玩耍内存映射文件相关推荐

  1. 内存映射文件 写入 卡住_在Java中使用内存映射文件时检测(写入)失败

    内存映射文件 写入 卡住 内存映射文件是一个很好的并且经常被忽视的工具. 我不会在这里详细介绍它们的工作方式(使用 力 Google Luke!),但我将快速总结其优势: 操作系统提供的延迟加载和写入 ...

  2. 在Java中使用内存映射文件时检测(写入)失败

    内存映射文件是一个很好的并且经常被忽视的工具. 我不会在这里详细介绍它们的工作方式(使用 力 Google Luke!),但我将快速总结其优势: 操作系统提供的延迟加载和写入缓存(您不必自己编写,并且 ...

  3. VC++中使用内存映射文件处理大文件

    引言 文件操作是应用程序最为基本的功能之一,Win32 API和MFC均提供有支持文件处理的函数和类,常用的有Win32 API的CreateFile().WriteFile().ReadFile() ...

  4. java 内存映射文件 主要应用_VC++中使用内存映射文件处理大文件(3)

    -- // 创建文件内核对象,其句柄保存于hFile HANDLE hFile = CreateFile("Recv1.zip", GENERIC_WRITE | GENERIC_ ...

  5. 【java】java中内存映射文件和IO

    转载:https://leokongwq.github.io/2017/02/25/java-memorymapped-file-and-io.html 对大多数Java开发人员来说,Java中的内存 ...

  6. Java基础:JavaNIO 之 内存映射文件原理

    1. 前言 最近研究Java中内存映射I/O.Java类库中的NIO中的内存映射文件MappedByteBuffer,相对于Java I/O是一个新的功能.特把适合用于处理大文件,在对大文件处理的时候 ...

  7. C#内存映射文件学习总结

    C#内存映射文件学习 http://www.cnblogs.com/flyant/p/4443187.html 内存映射文件是由一个文件到进程地址空间的映射. C#提供了允许应用程序把文件映射到一个进 ...

  8. 内存映射文件使用详细

    http://www.cppblog.com/woaidongmao/archive/2008/12/26/70439.html 摘要: 本文通过内存映射文件的使用来对大尺寸文件进行访问操作,同时也对 ...

  9. c++ 内存映射文件进程间共享数据

    int main(int argc, char *argv[])   {       //RecursiveDelete("C:\\20_128\\");       //Self ...

最新文章

  1. 微信小程序-设置启动页面
  2. 前端论坛、博客及公众号汇总
  3. 【算法】梯度消失与梯度爆炸
  4. 计算机办公应用高级教案,办公自动化高级应用电子教案.pdf
  5. 教你简单理解分布式与传统单体架构的区别
  6. 【python】抄写大神的百度贴吧代码
  7. 明知 | TypeScript 结合 egg.js 基本使用
  8. 公司盘点员工,不上班的员工要给钱吗?
  9. C++中的面向对象(二)
  10. matlab理论力学项目研究,基于MATLAB的机械力学问题的研究
  11. 第一篇博客--大学成长指南
  12. 介绍-Linux capability机制
  13. 一学就会的虚拟化技术之hyper-v桌面虚拟化
  14. SHAP:解释模型预测的通用方法
  15. 免费思维导图软件有哪些?2022值得一试的思维导图软件!
  16. 专注要事、把手弄脏、高效优雅是对抗规模化焦虑的好办法--读Getting Real(达成现实)和 Rework(重塑工作)
  17. Camera 主观画质测试(参考)
  18. 手持PDA操作系统有哪些?哪个系统好?
  19. 【硬件FPGA 】xilinx_A7调试问题总结(FPGA异常发烫)
  20. 中国车用尿素市场规模调研与发展趋势分析报告2022-2028年

热门文章

  1. yum php mysql5.5_CentOS 5.5使用yum来安装LAMP(php运行环境)
  2. html实现点赞效果,js实现点赞效果
  3. php拖拽上传大文件,如何实现文件拖拽上传
  4. 《学习JavaScript数据结构与算法》第三章 数组
  5. Vue3+CLI4 使用Element-ui
  6. Vue3 插槽使用详解
  7. 只会java_只会码代码的你和Java工程师之间的差距有大?
  8. java modal_Java 源码-模态对话框(Modal Dialog Box)的实现
  9. Oracle数据库的打开与关闭、后台进程
  10. php laravel 空白,php – Laravel View Make返回空白页面