Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么这个循环会破坏我的记忆?_C++_Windows_Winapi_Memory Mapped Files - Fatal编程技术网

C++ 为什么这个循环会破坏我的记忆?

C++ 为什么这个循环会破坏我的记忆?,c++,windows,winapi,memory-mapped-files,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 * sysI

我在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);
        }
    }
void Clear(){
int size=SizeB();
int iter=size/sysInfo.granB;
对于(int i=0;i
因此,它所做的是以最小的可寻址块(本例中为64k)遍历整个文件,映射视图,写入0,取消映射,重复。它工作正常,速度非常快,但当我使用它时,会有一些虚拟内存的使用

根据windows任务管理器,进程本身只使用了几兆字节,但当我在更大的文件上使用它时,“物理内存使用量”会激增。例如,在2GB文件上使用它足以让我的笔记本电脑陷入昏迷状态几分钟,物理内存使用率达到99%,task manager中的所有内容都在疯狂地减少内存,所有内容都会冻结一段时间

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

我试过两件事:

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

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

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

    然后,当您
    取消对文件
    的访问时,操作系统将获得相关内存范围的所有权,并将用户空间现在无法访问的数据写回磁盘(当然,假设您已将其写入,这会将页面标记为“脏”,否则它将被直接释放)。引用(我请您在评论中阅读):
    修改过的页面被“惰性地”写入磁盘;也就是说,修改可以缓存在内存中,稍后写入磁盘。

    取消映射文件视图并不保证“取消提交”并将数据写入磁盘。此外,即使
    CloseHandle
    也不能提供这种保证。它只是关闭了它的手柄。由于缓存机制,如果不调用,操作系统完全可以在自己的时间将数据写回磁盘。即使重新打开同一个文件,也可能只是从缓存中而不是从磁盘中提取数据

    归根结底,问题在于

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

  • 当你睡觉时,你会看到更好的性能,因为你让操作系统有机会说“嘿,我什么都没做……让我们继续刷新缓存吧”,这迫使磁盘IO大致按顺序进行。

    @user81993因为你在使用这些函数,并且在使用大文件时抱怨内存使用情况。这对我来说意味着你不知道函数实际上做了什么。如果你能告诉我他们是做什么的,以及如何做的,那么我想你最终会回答你自己的问题,而不是暗示对方是愚蠢的,你为什么不告诉我们你为什么要使用
    MapViewOfFile
    来读/写文件,而不是使用标准的文件I/O机制,尽量使用真正大的块,比如2Gb。@David所有这些都很好(甚至是可取的)。但很明显,系统无法应对(这就是问题所在),由此产生的内存压力应该会导致系统从物理内存中删除这些页面。不这样做听起来像是系统内存处理程序中一个相当严重的性能缺陷,除非有人能解释为什么系统没有正确地预测到这种使用模式——这让我们回到了OP的实际问题。我在文档中看不到任何东西(或者我在使用MMFs时记得的东西)这表明这是合理的行为。您正在以非常高的速率生成脏RAM页,相当于2G字节。在将其内容写入文件之前,它们不能用于任何其他用途。一个典型的笔记本电脑主轴驱动器是脆弱的,你很幸运能获得2 MB/秒的速度,因此可以让驱动器保持忙碌15分钟。操作系统必须处理相当低的内存量,而在这种情况下,操作系统又被迫取消内存