C++ 无法在我的 Windows 应用程序中重写共享内存。它分配新的内存
Posted
技术标签:
【中文标题】C++ 无法在我的 Windows 应用程序中重写共享内存。它分配新的内存【英文标题】:C++ cannot rewrite shared memory in my windows app. It allocates new memory 【发布时间】:2014-02-14 17:25:38 【问题描述】:C++ 中的共享内存对我来说是新事物,还在学习中,现在我发现它并没有按我的预期工作。我想实现一个名为 CharBuffer 的类,它通过 CreateFileMapping 和 MapViewOfFile 函数将 char 数组映射到共享内存:
HANDLE hBuffer = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, shmBufferName);
char * buffer = (char *) MapViewOfFile(hBuffer, FILE_MAP_ALL_ACCESS, 0, 0, size);
向缓冲区添加字节是通过调用CharBuffer函数“add”实现的:
void CharBuffer::add(char * data, size_t size)
memcpy(&buffer[0], &data[0], size);
没有检查数据大小,但这没问题,它只是我用于学习共享内存的测试应用程序。 没关系,我可以成功地将字节添加到缓冲区或从缓冲区读取 - 没有错误,没有问题。我正在使用 CharBuffer 的 第一个 实例。
但现在我想用 second 的 CharBuffer 实例打开共享内存并读取或重写共享内存中的数据。对于我使用的开放和映射内存:
HANDLE hBuffer = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, shmBufferName);
char * buffer = (char *) MapViewOfFile(hBuffer, FILE_MAP_ALL_ACCESS, 0, 0, size);
打开过程中没有错误。现在我要解决我的问题了。在 first 实例中,我将 64 MB 复制到共享内存。当我尝试使用 second 实例逐字节读取它们时,该实例具有正确映射的共享内存(它可以打印数据),但在资源监视器中我可以看到我有两倍多的内存 - 128 MB。第一次添加数据后,内存占用了 64 MB,但在通过第二个实例打印数据期间,内存增加了下一个 64 内存。
同样的问题是使用第二个实例将数据写入内存。
我的目标是限制共享内存并通过两个或多个 CharBuffer 实例使用它(读/写)。您能否解释一下问题出在哪里或如何实现我想要的?
非常感谢。
【问题讨论】:
当您说“第二个实例”时,您是指您的程序的另一个副本吗? 没有。只需创建 CharBuffer bfr1 然后调用 bfr1.add(data, size) 然后创建 CharBuffer bfr2 并读取数据。全部在一份程序的主要功能中。 您打开了两个映射到同一个共享映射。尝试对两者使用相同的映射 HANDLE。 您的意思是使用一个由两个 CharBuffers 共享的 HANDLE?我会试试的。 @babusek - 那么你不必做任何远程特别的事情 - 它已经全部共享了。 【参考方案1】:我从未使用内存映射文件来降低内存消耗。我认为您的问题是 MapViewOfFile 始终返回指向唯一地址空间的指针,这将修改您页面文件中的相同页面。我试图在 MSDN 中找到证明,我发现的只是这篇文章:
http://msdn.microsoft.com/en-us/library/ms810613.aspx
我想可以解释一下:
如上所述,您可以拥有相同的多个视图 内存映射文件,它们可以重叠。但是映射两个呢 同一个内存映射文件的相同视图?学会如何做之后 取消映射文件的视图,您可以得出这样的结论: 在一个进程中不可能有两个相同的视图 因为他们的基地址是一样的,而你不能 来区分它们。这不是真的。请记住,基础 MapViewOfFile 或 MapViewOfFileEx 返回的地址 函数不是文件视图的基地址。相反,它是 视图开始的进程中的基地址。所以映射两个 相同内存映射文件的相同视图将产生两个视图 具有不同的基地址,但仍然具有相同的视图 内存映射文件的同一部分。
这个小练习的目的是强调每个视图 单个内存映射文件对象总是映射到一个唯一的范围 处理中的地址。每个人的基地址都不同 看法。出于这个原因,映射视图的基地址就是 需要取消映射视图。
因此 MapViewOfFile 将地址返回到一旦提交将分配其自己的物理内存的内存,这实际上会增加您的进程内存消耗 - 正如您所描述的那样。
[编辑]
实际上,我开始看到即使 MapViewOffFile 都将地址返回到唯一的虚拟地址空间,它们都由相同的物理 RAM 页面支持。您可以通过Memory-Mapped Files and Coherence
中的 c/c++ 在 Windows 中阅读此内容:
如果多个进程正在映射单个数据文件的视图,则 数据仍然是连贯的,因为仍然只有一个实例 数据文件中的每一页 RAM — 只是 RAM 的页 映射到多个进程地址空间。
以下博客中的技巧也证明了这一点:
http://blogs.msdn.com/b/oldnewthing/archive/2003/10/07/55194.aspx
资源监视器显示您每次访问文件视图时内存消耗过高的事实是,它显示了工作集大小,据我了解,它可能会显示两次共享内存。
【讨论】:
感谢您对问题的描述。但现在我尝试了这个:我对两个 CharBuffers 只使用了一个 HANDLE,添加数据后我做了 UnmapViewOfFile 和 CloseHandle,然后在下一个 CharBuffer 打开相同的句柄并正确地从缓冲区读取数据。在读取过程中内存再次增加,但由于之前调用 UnmapViewOfFile 减少了内存,它只达到了 64 MB。这是解决我问题的正确方法吗? 我认为一旦你从 CreateFileMapping 处理 CloseHandle,你也会从页面文件中释放保留的页面。所以不要关闭句柄。 是的,我也一样,但我不明白为什么我仍然可以读取结果。 也许它还在您的页面文件中? - 我更新了我的答案,看起来你最初的假设实际上是正确的以上是关于C++ 无法在我的 Windows 应用程序中重写共享内存。它分配新的内存的主要内容,如果未能解决你的问题,请参考以下文章