在 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# 中使用内存映射文件时是不是可以避免数据副本?的主要内容,如果未能解决你的问题,请参考以下文章
使用内存映射文件或普通 Stream.Write 时是不是有任何持久性保证