在 C# 中使用内存映射文件时是不是可以避免数据副本?

Posted

技术标签:

【中文标题】在 C# 中使用内存映射文件时是不是可以避免数据副本?【英文标题】:Is it possible to avoiding copies of data when using memory mapped files in C#?在 C# 中使用内存映射文件时是否可以避免数据副本? 【发布时间】:2012-05-14 22:27:07 【问题描述】:

我对 C# 中内存映射文件如何工作的理解是,每个数据请求都会产生一个副本。例如,如果您将大型数据结构作为文件持久化,则使用内存映射文件将导致实际文件映射到 RAM 的内存,并且一旦从文件中读取,副本就会驻留在 GC 堆中。

我假设这是因为指针和 GC 通常不能很好地结合在一起。

那么,有没有办法解决这个问题?

也许通过一些混合模式 C++ 可以在内存映射数据上公开托管 API? 使用不安全的 C# 直接操作指针会怎样?

我试图解决的一般问题是在多个进程之间共享一个大型数据结构。数据结构用于回答一小部分“问题”,这些问题可以作为简单的 API 公开(即基本上是一堆其他数据的高度专业化索引)。

顺便说一句,这不会使 .NET API 对于“共享大量数据”的场景毫无用处吗?

【问题讨论】:

code.msdn.microsoft.com/windowsdesktop/… 您是否一次将整个文件读入 .NET 应用程序?如果您根据需要读取内存映射文件的部分内容,您会分配很多小缓冲区,但这并不像您想象的那么昂贵。可以避免复制,但复制的开销真的是个问题吗? 我的 .NET 应用程序可以通过多种方式非常有效地“共享大量数据”,包括内存映射文件。特别是,一个套件共享超过 8 GB 的内存,这些程序的总内存使用量惊人地接近 8 GB。 我会立即阅读全部内容。如果我在每个需要数据结构的进程中制作一个副本,那么我没有从使用 MMF 中保存任何东西,还不如使用文件流。 【参考方案1】:

您可以使用不安全代码直接访问映射的内存。我建议您查看“blittable structs”,它们是可以在内存中复制而无需修改的结构类型。这是一个例子:

struct MyDataRecord  public int X, Y; 

...

for (var i = 0 .. 10) 
 ((MyDataRecord*)pointerToUnmanagedMemory)[i] = new MyDataRecord()  X = i, Y = i * i ;

这是非常高效和方便的。

【讨论】:

嗯,您跳过了确保进程不会读取正在写入的数据所需的命名互斥锁。这有把“方便”扔出窗外的诀窍。并杀死性能。 看起来不安全的代码和 blittable 结构将是要走的路......谢谢@usr。在我的搜索中包含“不安全”后,我也发现了这个:***.com/questions/7956167/…

以上是关于在 C# 中使用内存映射文件时是不是可以避免数据副本?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Protobuf 和内存映射文件 C# 的 IPC

使用内存映射文件或普通 Stream.Write 时是不是有任何持久性保证

读取内存内存映射文件 C++ 和 C#

C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped

如何动态扩展内存映射文件

C#大文件读取和查询--内存映射