原文链接 : 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, outnewContainer);}

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

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

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

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. .NET 4.0中使用内存映射文件实现进程通讯

    操作系统很早就开始使用内存映射文件(Memory Mapped File)来作为进程间的共享存储区,这是一种非常高效的进程通讯手段.Win32 API中也包含有创建内存映射文件的函数,然而,这些函数都 ...

  2. C++中使用内存映射文件处理大文件

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

  3. Delphi 中内存映射对于大文件的使用

    这篇文章主要介绍了Delphi 中内存映射对于大文件的使用的相关资料,希望通过本文能帮助到大家,需要的朋友可以参考下 Delphi 中内存映射对于大文件的使用 平时很少使用大文件的内存映射,碰巧遇到了 ...

  4. C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped 转 VC中进程与进程之间共享内存 .net环境下跨进程、高频率读写数据 使用C#开发Android应用之WebApp 分布式事务之消息补偿解决方案

    C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped 转 节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing). ...

  5. 内存映射文件MemoryMappedFile使用

    参考资料: http://blog.csdn.net/bitfan/article/details/4438458 所谓内存映射文件,其实就是在内存中开辟出一块存放数据的专用区域,这区域往往与硬盘上特 ...

  6. python 中内存映射二进制文件

    内存映射一个文件并不会导致整个文件被读取到内存中. 也就是说,文件并没有被复制到内存缓存或数组中.相反,操作系统仅仅为文件内容保留了一段虚拟内存. 当你访问文件的不同区域时,这些区域的内容才根据需要被 ...

  7. 第17章 内存映射文件(3)_稀疏文件(Sparse File)

    17.8 稀疏调拨的内存映射文件 17.8.1 稀疏文件简介 (1)稀疏文件(Sparse File):指的是文件中出现大量的0数据,这些数据对我们用处不大,但是却一样的占用空间.NTFS文件系统对此 ...

  8. 《Java核心技术卷二》笔记(二)文件操作和内存映射文件

    文件操作 上一篇已经总结了流操作,其中也包括文件的读写.文件系统除了读写以为还有很多其他的操作,如复制.移动.删除.目录浏览.属性读写等.在Java7之前,一直使用File类用于文件的操作.Java7 ...

  9. 内存映射文件详解-----C++实现

    先不说内存映射文件是什么.贴个代码先,. #include <iostream> #include <fcntl.h> #include <io.h> #inclu ...

随机推荐

  1. SDN网络虚拟化、资源映射等相关论文粗读

    1. Control Plane Latency with SDN Network Hypervisors: The Cost of Virtualization 年份:2016 来源:IEEE NE ...

  2. XMLHttpRequest详解

    XMLHttpRequest详解: https://xhr.spec.whatwg.org/

  3. Ubuntu16.04.3安装以及简单配置使用

    1. 官网下载ubuntu16.04.3的iso 2.上传至esxi 3. 中文安装界面有问题,使用english进行安装. 4. server版本的应该不带gui的界面进行安装... 5.使用非ro ...

  4. 手动安装ettercap的过程

    知乎推送了一个中间人攻击的软件 ettercap 想着尝试进行一下安装学习, 如果有机会的话安全测试部分应该用的到. 1. 下载: wget https://codeload.github.com/E ...

  5. Lodop打印设计(PRINT_DESIGN)里的快捷键

    Lodop打印控件,给开发人员提供了可视化编辑工具,编辑后可生成代码,然后复制到自己程序代码中,让开发更简单,打印设计中有一些快捷键也能让开发更便捷. 打印设计快捷键:ctrl 多个选中Shift 左 ...

  6. Bootstrap辅助类

    前面的话 Bootstrap提供了一组工具类,用于辅助项目的开发.本文将详细介绍Bootstrap辅助类 文本色 通过颜色来展示意图,Bootstrap 提供了一组工具类.这些类可以应用于链接,并且在 ...

  7. BZOJ2325[ZJOI2011]道馆之战——树链剖分+线段树

    题目描述 口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中 的每一个冰块都只能经过一次.当一个冰地上的所有冰块都被经过之后,到下一个冰地的楼梯才 ...

  8. Python 面向对象 - 内置类方法

    内置方法  内置方法  说明  __init__(self,...)  初始化对象,在创建新对象时调用  __del__(self)  释放对象,在对象被删除之前调用  __new__(cls,*ar ...

  9. MT【232】展开式中的系数

    $(1+x+x^2+\cdots+x^{100})^3$展开式中$x^{150}$前的系数为_____ 解答:$(1+x+x^2+\cdots+x^{100})^3=(1-x^{101})^3\sum ...

  10. LOJ #2718. 「NOI2018」归程(Dijkstra + Kruskal重构树 + 倍增)

    题意 给你一个无向图,其中每条边有两个值 \(l, a\) 代表一条边的长度和海拔. 其中有 \(q\) 次询问(强制在线),每次询问给你两个参数 \(v, p\) ,表示在 \(v\) 出发,能开车 ...