C# MemoryMappedFile使用方法 C#如何实现内存映射文件进行IPC

3次阅读

unauthorizedaccessexception主因是ntfs acl权限不足,需确保文件存在、有fileiopermission且无独占打开;命名映射跨进程通信须名称完全一致、用createoropen、配eventwaithandle同步。

C# MemoryMappedFile使用方法 C#如何实现内存映射文件进行IPC

MemoryMappedFile.CreateFromFile 为什么总抛出 UnauthorizedAccessException

权限不足是 windows 上最常见的报错,尤其在非管理员账户下尝试映射只读文件、系统保护路径(如 C:Windows)或 NTFS 权限受限的目录时。UnauthorizedAccessException 并不总意味着代码写错了,而是访问控制列表(ACL)没放行。

  • 确保目标文件已存在且进程有 FileIOPermissionReadReadWrite 权限
  • 若映射到文件后备(backed)模式,文件不能被其他进程以冲突模式打开(例如另一进程用 FileShare.None 独占打开)
  • 避免映射网络路径(UNC)——MemoryMappedFile 不支持远程文件,会静默失败或抛异常
  • 调试时可用 Process Monitor 查看具体哪类访问被拒绝(如 Desired Access: ReadAttributes

如何用 CreateOrOpen 配合命名映射实现跨进程通信

命名内存映射文件是 C# IPC 最轻量的方案之一,本质是内核对象共享。关键不在“创建”,而在“名字一致 + 访问同步”。

  • 服务端调用 MemoryMappedFile.CreateOrOpen("MyIPCMap", 1024),客户端用完全相同的名称调用同名方法即可连接
  • 名字区分大小写,且全局唯一;建议加前缀如 "GlobalMyApp_IPC_v1" 避免与其他应用冲突
  • 必须配合 MemoryMappedViewAccessor 才能读写数据,且多个进程不能同时用同一个 Accessor 实例操作——每个进程需独立 .CreateViewAccessor()
  • 没有内置消息边界,需自行约定协议:比如前 4 字节存长度,后续为 UTF8 字符串;否则容易读到脏数据

MemoryMappedViewAccessor.WriteArray 性能差?改用指针操作更稳

WriteArray<t></t>ReadArray<t></t> 内部做了数组拷贝和类型检查,小数据还行,高频 IPC 场景下 GC 压力和复制开销明显。

  • 启用 unsafe 后,用 Accessor.SafeMemoryMappedViewHandle.DangerousGetHandle() 获取句柄,再通过 Marshal.UnsafeAddrOfPinnedArrayElementSpan<byte>.DangerousCreate</byte> 构建可读写视图
  • 务必保证 Accessor 生命周期长于指针使用期,否则句柄提前释放会导致 AccessViolationException
  • 简单场景下,直接用 Accessor.WriteInt32(0, value)Accessor.ReadString(4, Encoding.UTF8) 比数组更可控,也避免序列化开销

为什么进程退出后映射还在,新进程连不上同名映射

Windows 内核对象(包括命名 MemoryMappedFile)生命周期由引用计数控制,不是靠进程存活。但常见误操作会让“名字看似相同实则不同”:

  • 服务端用 CreateOrOpen 创建,客户端却用 CreateFromFile —— 后者不认名字,只认文件路径,根本不会去查命名对象表
  • 一个进程用 "MyMap",另一个用 "myMap"(大小写不同),Windows 视为两个对象
  • 未显式调用 Dispose(),导致对象句柄泄漏;重启前可用 Handle.exe -a | findstr "Section" 查残留句柄
  • UWP 应用默认运行在 AppContainer 沙箱中,无法访问普通命名映射,需用 Local 前缀并配置能力声明

实际用下来,最易忽略的是同步点:MemoryMappedFile 本身不提供信号机制。两个进程得额外配 EventWaitHandle 或轮询标志位,否则极易出现“数据已写入但对方还没读”的竞态。

text=ZqhQzanResources