前言

MemoryMappedFile(简称MMF)类是.NET中对内存映射文件进行操作的类,内存映射文件是非常高效的本地IO方案,由操作系统提供内存与IO文件之间的映射转换,对内存映射文件的更改由操作系统自动与物理文件进行高效的数据交换。在大文件处理中一般都需要使用到它,同时它也被用来做高效的进程间通讯的底层技术。

正因为它是如此的高效和便捷,所以在服务器程序开发中被广泛使用到。譬如,我们实现的基于Socket网络通讯程序中,在发送大数据时,需要对数据进行拆包组包的操作,这就往往需要对未接收完全的数据包进行缓存,在这个的场景中最好是使用MMF手动来对通讯包数据的缓存管理,倘若直接把这些数据放在.NET内置的集合、列表或字典中,那很可能会把.NET托管内存撑爆的。

当我把基于Socket的通讯类库代码运行在Mono on Linux中的时候,发现其使用到的MMF代码运行时异常了,本文就是对这一问题的处理过程的记录。

问题说明

Mono on Linux

我的代码是通过指定文件路径的方式创建MMF的,譬如文件路径为:/tmp/Zongsoft.Communication.Net#1.cache,在Windows中运行的很正常,但是在Mono on Linux中发生运行时异常:

Unhandled Exception:
System.IO.FileNotFoundException: 没有那个文件或目录 ---> Mono.Unix.UnixIOException: 没有那个文件或目录 [ENOENT].
    at Mono.Unix.UnixMarshal.ThrowExceptionForLastError () [0x00000] in :0
    at System.IO.MemoryMappedFiles.MemoryMapImpl.Open (System.String path, FileMode mode, Int64 capacity, MemoryMappedFileAccess access) [0x00000] in :0
    at System.IO.MemoryMappedFiles.MemoryMappedFile.CreateFromFile (System.String path, FileMode mode, System.String mapName, Int64 capacity, MemoryMappedFileAccess access) [0x00000] in :0

难道在Mono中,需要先创建MMF对应的物理文件?好吧,那我就手动在临时文件夹下创建一个指定名称的空文件后,再来跑一遍,结果报了这个:

Unhandled Exception:
System.ArgumentException: capacity
    at System.IO.MemoryMappedFiles.MemoryMapImpl.Open (System.String path, FileMode mode, Int64 capacity, MemoryMappedFileAccess access) [0x00000] in :0
    at System.IO.MemoryMappedFiles.MemoryMappedFile.CreateFromFile (System.String path, FileMode mode, System.String mapName, Int64 capacity, MemoryMappedFileAccess access) [0x00000] in :0

难道是Mono对通过文件路径来创建MMF支持不力?好吧,那就试试通过文件流的方式来创建MMF吧,结果还是不行:

Unhandled Exception:
System.ArgumentException: capacity
at System.IO.MemoryMappedFiles.MemoryMappedFile.CreateFromFile (System.IO.FileStream fileStream, System.String mapName, Int64 capacity, MemoryMappedFileAccess access, System.IO.MemoryMappedFiles.MemoryMappedFileSecurity memoryMappedFileSecurity, HandleInheritability inheritability, Boolean leaveOpen) [0x00000] in :0

看来,应该是跟capacity与物理文件的大小不匹配所致,好吧,那就在创建完文件流后,再使用文件流的SetLength来指定一个长度后,再通过该特定长度的文件流来创建MMF吧,结果果然创建成功!这说明在Mono中的创建MMF时,传入的目标文件必须是已经存在,且该文件长度不能为零。

由于刚才那个文件流的长度正好与创建MMF时capacity参数值相同,那么接下来我再来测试下,当文件流的长度与创建MMF时指定的capacity数值不同时,分别会发生什么情况。

1、文件流的长度大于创建MMF时capacity,成功,并且MMF创建后不会改变对应文件流的大小;

2、文件流的长度小于创建MMF时capacity:

Unhandled Exception:
System.ArgumentException: capacity
    at System.IO.MemoryMappedFiles.MemoryMappedFile.CreateFromFile (System.IO.FileStream fileStream, System.String mapName, Int64 capacity, MemoryMappedFileAccess access, System.IO.MemoryMappedFiles.MemoryMappedFileSecurity memoryMappedFileSecurity, HandleInheritability inheritability, Boolean leaveOpen) [0x00000] in :0

.NET on Windows

再简单说明下MemoryMappedFile类在.NET Windows平台中的创建行为:

  1. 通过文件路径的方式,如果对应的文件不存在则自动创建一个对应指定capacity大小的文件。
  2. 通过文件流的方式,如果对应文件流的大小小于capacity则成功;如果对应文件流大小大于capacity则失败,提示指定的文件流大小太小。

Mono 源码简查

通过查看Mono-3.0.12的源码,发现MMF类的如下代码:

public static MemoryMappedFile CreateNew(string mapName, long capacity, MemoryMappedFileAccess access,
        MemoryMappedFileOptions options, MemoryMappedFileSecurity memoryMappedFileSecurity,
        HandleInheritability inheritability)
{
    return CreateFromFile(mapName, FileMode.CreateNew, mapName, capacity, access);
}

public static MemoryMappedFile CreateOrOpen(string mapName, long capacity, MemoryMappedFileAccess access)
{
    return CreateFromFile(mapName, FileMode.OpenOrCreate, mapName, capacity, access);
}

可见它们是都是通过CreateFromFile方法来处理的,并且将mapName作为文件路径来使用,所以,调用这两个方法要留心了,因为它与.NET(Windows)平台的实现是完全不同的,除此以外的其他创建或打开方法未实现,请勿使用!代码如下:

public static MemoryMappedFile OpenExisting(string mapName, MemoryMappedFileRights desiredAccessRights, HandleInheritability inheritability)
{
    throw new NotImplementedException();
}

总结

综上所述,为了让代码能够在Linux和Windows平台都正常运行,建议统一使用

MemoryMappedFile.CreateFromFile(

    FileStream fileStream,
    String mapName,
    Int64 capacity,
    MemoryMappedFileAccess access,
    System.IO.MemoryMappedFiles.MemoryMappedFileSecurity memoryMappedFileSecurity,
    HandleInheritability inheritability,
    Boolean leaveOpen
)

方法来创建MMF,并且在调用前确保指定的文件流大小与capacity参数值相同。

MemoryMappedFile 在 Mono in Linux 的开发笔记的更多相关文章

  1. 嵌入式linux驱动开发 笔记

    @ 目录 首个驱动hellodrv 1.编写源码 2.编译模块 3.加载驱动 首个驱动hellodrv 3.如果下载不到,就自己编写,并编译驱动. 1.编写源码 2.编译模块 1.先写makefile ...

  2. 驱动开发学习笔记. 0.06 嵌入式linux视频开发之预备知识

    驱动开发读书笔记. 0.06  嵌入式linux视频开发之预备知识 由于毕业设计选择了嵌入式linux视频开发相关的项目,于是找了相关的资料,下面是一下预备知识 UVC : UVC,全称为:USB v ...

  3. Linux及Arm-Linux程序开发笔记(零基础入门篇)

    Linux及Arm-Linux程序开发笔记(零基础入门篇)  作者:一点一滴的Beer http://beer.cnblogs.com/ 本文地址:http://www.cnblogs.com/bee ...

  4. 【Linux开发】Linux及Arm-Linux程序开发笔记(零基础入门篇)

    Linux及Arm-Linux程序开发笔记(零基础入门篇) 作者:一点一滴的Beer http://beer.cnblogs.com/ 本文地址:http://www.cnblogs.com/beer ...

  5. 嵌入式linux应用开发完全手册学习笔记一

    2015.3.25星期三 晴 有两个星期没写学习日记了,找个时间把这段时间做的电子词典和ARM小项目总结一下. 下面的知识点总结,U-BOOT:参考PDF文档:嵌入式linux应用开发完全手册 当虚拟 ...

  6. Linux实战教学笔记08:Linux 文件的属性(上半部分)

    第八节 Linux 文件的属性(上半部分) 标签(空格分隔):Linux实战教学笔记 第1章 Linux中的文件 1.1 文件属性概述(ls -lhi) linux里一切皆文件 Linux系统中的文件 ...

  7. Linux实战教学笔记03:操作系统发展历程及系统版本选择

    标签(空格分隔): Linux实战教学笔记-陈思齐 第1章 Linux简介 1.1 什么是操作系统? 简单讲:操作系统就是一个人与计算机硬件的中介. 操作系统,英文名称Operating System ...

  8. Linux实战教学笔记02:计算机系统硬件核心知识

    标签(空格分隔):Linux实战教学笔记-陈思齐 第1章 互联网企业常见服务器介绍 1.1 互联网公司服务器品牌 - DELL(大多数公司,常用) - HP - IBM(百度在用) 浪潮 联想 航天联 ...

  9. storysnail的Linux串口编程笔记

    storysnail的Linux串口编程笔记 作者 He YiJun – storysnail<at>gmail.com 团队 ls 版权 转载请保留本声明! 本文档包含的原创代码根据Ge ...

随机推荐

  1. 关于DOM的操作以及性能优化问题-重绘重排

     写在前面: 大家都知道DOM的操作很昂贵. 然后贵在什么地方呢? 一.访问DOM元素 二.修改DOM引起的重绘重排 一.访问DOM 像书上的比喻:把DOM和JavaScript(这里指ECMScri ...

  2. node.js学习(三)简单的node程序&&模块简单使用&&commonJS规范&&深入理解模块原理

    一.一个简单的node程序 1.新建一个txt文件 2.修改后缀 修改之后会弹出这个,点击"是" 3.运行test.js 源文件 使用node.js运行之后的. 如果该路径下没有该 ...

  3. node中的cmd规范

    你应该熟悉nodejs模块中的exports对象,你可以用它创建你的模块.例如:(假设这是rocker.js文件) exports.name = function() { console.log('M ...

  4. scrapy爬虫docker部署

    spider_docker 接我上篇博客,为爬虫引用创建container,包括的模块:scrapy, mongo, celery, rabbitmq,连接https://github.com/Liu ...

  5. ASP.NET WebApi OWIN 实现 OAuth 2.0

    OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用. OAuth 允许用户提供一个令牌, ...

  6. 水平可见直线 bzoj 1007

    水平可见直线 (1s 128M) lines [问题描述] 在xoy直角坐标平面上有n条直线L1,L2,...Ln,若在y值为正无穷大处往下看,能见到Li的某个子线段,则称Li为可见的,否则Li为被覆 ...

  7. “老坛泡新菜”:SOD MVVM框架,让WinForms焕发新春

    火热的MVVM框架 最近几年最热门的技术之一就是前端技术了,各种前端框架,前端标准和前端设计风格层出不穷,而在众多前端框架中具有MVC,MVVM功能的框架成为耀眼新星,比如GitHub关注度很高的Vu ...

  8. (资源整理)带你入门Spark

    一.Spark简介: 以下是百度百科对Spark的介绍: Spark 是一种与 Hadoop 相似的开源集群计算环境,但是两者之间还存在一些不同之处,这些有用的不同之处使 Spark 在某些工作负载方 ...

  9. 排序算法----调用库函数qsort进行快速排序

    功 能: 快速排序 头文件:stdlib.h 用 法: void qsort(void *base,int nelem,int width,int (*fcmp)(const void *,const ...

  10. 学习笔记:发现一个IE版本判断的好方法

    web开发就不得不面对浏览器兼容性问题,特别是IE的兼容问题.在前端代码中经常要处理一些兼容格式,为了解决这个问题网上找了找识别浏览器版本的方法.   常规js方法 找到一个方法,还不错,可以识别出各 ...