c++ - 为什么这个循环会破坏我的内存?

标签 c++ windows winapi memory-mapped-files

我的 MMF 类中有这个函数

    void Clear() {
        int size = SizeB();
        int iter = size / sysInfo.granB;
        for (int i = 0; i < iter; i++) {
            auto v = (char*)MapViewOfFile(hMmf, FILE_MAP_READ | (write ? FILE_MAP_WRITE : 0), 0, i * sysInfo.granB, sysInfo.granB);
            std::memset(v, 0, sysInfo.granB);   
            UnmapViewOfFile(v);
        }
    }

所以它所做的是以最小的可寻址 block (在本例中为 64k)遍历整个文件,映射 View ,写入 0,取消映射,重复。它工作正常并且速度非常快,但是当我使用它时,会出现一些幻象内存使用情况。

根据 Windows 任务管理器,进程本身只使用了几兆字节,但当我在较大的文件上使用它时,“物理内存使用量”猛增。例如,在一个 2GB 的文件上使用它足以让我的笔记本电脑昏迷几分钟,物理内存使用率达到 99%,任务管理器中的所有内容都在疯狂减少内存并且所有内容都会卡住一段时间。

我尝试在 64k block 中执行此操作的全部原因是为了降低内存使用量,但在这种情况下 block 大小并不重要,覆盖文件的任何大小块 * n 都会做同样的事情。

我尝试过的一些事情:

  1. 在取消映射之前刷新 View - 这会使事情变得非常缓慢,以任何大小的 block 处理 2gb 文件大约需要 10 分钟。
  2. 在循环中添加硬编码延迟 - 它实际上工作得很好,它仍然可以在几秒钟内完成,内存使用率保持较低,但我真的不喜欢任何循环中硬编码延迟的概念
  3. 只在文件末尾写入 0 - 我实际上不需要清除文件,而只是强制它准备好使用。我的意思是 - 当我创建一个新文件并从我的随机 IO 开始时,我最多只能得到 ~1MB/s。如果我打开一个现有文件或先在新文件中强制写入 0,我会获得更快的速度。我不太确定为什么会这样,但另一个线程中的用户建议在设置文件指针后向文件的末尾写入一些内容与清除具有相同的效果,但从测试来看,这是不正确的。

所以目前我正在尝试从清除文件而不破坏计算机内存的角度来解决这个问题。有人知道如何适本地限制该循环吗?

最佳答案

事情是这样的。当您 MapViewOfFile 时,它会分配关联的内存范围,但可能可能会将其标记为已换出(例如,如果它尚未读入内存)。如果是这种情况,那么当您第一次访问它时会遇到页面错误(这将导致操作系统读取它)。

然后,当您UnmapViewOfFile 时,操作系统会取得相关内存范围的所有权,并将用户空间现在不可访问的数据写回磁盘(当然,假设您已经写入它,将页面标记为“脏”,否则直接取消分配)。引用the documentation (我要求您在评论中阅读):修改后的页面“延迟”写入磁盘;也就是说,修改可能会缓存在内存中,稍后写入磁盘。

取消映射文件 View 不能保证“取消提交”并将数据写入磁盘。此外,即使 CloseHandle 也不提供该保证。它只是关闭它的句柄。由于缓存机制,如果您不调用 FlushViewOfFile,操作系统完全可以自行将数据写回磁盘。 .即使重新打开同一个文件,也可能只是从缓存中而不是从磁盘中拉回数据。

最终的问题是

  1. 你内存映射一个文件
  2. 你写入内存映射
  3. 写入内存映射的地址范围会导致从磁盘读取文件的映射
  4. 您取消映射文件
  5. “延迟”取消映射文件将数据写回磁盘
  6. 操作系统可能达到内存压力,发现有一些未写入的数据现在可以写入磁盘,并强制发生这种情况以恢复物理内存以进行新分配;顺便说一句,由于操作系统延迟刷新,您的 IO 不再是顺序的,导致主轴磁盘延迟急剧增加

您在 sleep 时会看到更好的性能,因为您让操作系统有机会说“嘿,我什么都没做……让我们继续刷新缓存”,这会强制磁盘 IO 大致按顺序进行。

关于c++ - 为什么这个循环会破坏我的内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35776217/

相关文章:

c++ - C++ 获取指针指向的变量名称

c++ - 如何在不切断图像部分的情况下围绕中心旋转 QPixmap

python - 在 Python 中确定正在运行的程序

windows - 如何从第 x 行读取文件到第 y 行(dos/win 批处理文件)

c# - 弹出UAC消息时屏幕颜色默认为正常(无法检测到)

c++ - typedef 一个可在 Windows 和 Linux 上使用的 C++ 函数

c++ - C/C++ 帮助在 C 中处理多个文件

c++指向基类的 vector 指针,以及访问多个派生类的方法

mysql - WordPress:MySQL 数据库和 UNC 共享

winapi - 在 Windows API 中设置菜单的宽度