C++ 以相反的顺序读取fread()文件会导致内存泄漏吗?

C++ 以相反的顺序读取fread()文件会导致内存泄漏吗?,c++,c,io,low-level,C++,C,Io,Low Level,我有一个基本上做到这一点的程序: 打开一些二进制文件 使用4MB数据块向后读取文件(所谓向后,我的意思是它在EOF附近开始,并在文件开始处结束读取,即“从右向左”读取文件) 关闭文件 我的问题是:为什么内存消耗如下所示,即使在我附加的代码中没有明显的内存泄漏 以下是为获得上述图像而运行的程序源: #包括 #包括 内部主(空) { //分配物品 const int bufferSize=4*1024*1024; FILE*fileHandle=fopen(“./input.txt”,“rb”);

我有一个基本上做到这一点的程序:

  • 打开一些二进制文件
  • 使用4MB数据块向后读取文件(所谓向后,我的意思是它在EOF附近开始,并在文件开始处结束读取,即“从右向左”读取文件)
  • 关闭文件
  • 我的问题是:为什么内存消耗如下所示,即使在我附加的代码中没有明显的内存泄漏

    以下是为获得上述图像而运行的程序源:

    #包括
    #包括
    内部主(空)
    {
    //分配物品
    const int bufferSize=4*1024*1024;
    FILE*fileHandle=fopen(“./input.txt”,“rb”);
    如果(!fileHandle)
    {
    fprintf(stderr,“没有您需要的文件”);
    返回1;
    }
    unsigned char*buffer=新的unsigned char[bufferSize];
    如果(!缓冲区)
    {
    fprintf(stderr,“您没有缓冲区”\n);
    返回1;
    }
    //获取文件大小。文件可能很大,因此使用fseeko()和ftello()
    //而不是fseek()和ftell()。
    fseeko(文件句柄,0,SEEK_END);
    off_t totalSize=ftello(文件句柄);
    fseeko(文件句柄,0,SEEK_集);
    //以相反的顺序读取文件。这很重要。
    对于(off_t pos=totalSize-bufferSize,j=0;
    pos>=0;
    pos-=缓冲区大小,j++)
    {
    如果(j%10==0)
    {
    fprintf(标准,
    “疯狂阅读:%lld/%lld\n”,
    pos,总尺寸);
    }
    /*
    *下面是问题的核心。请参见下面的注释
    */
    //寻找理想的位置
    fseeko(文件句柄、位置、搜索集);
    //读这段话
    fread(buffer,sizeof(unsigned char),bufferSize,fileHandle);
    }
    fclose(文件句柄);
    删除[]缓冲区;
    }
    
    我也有以下意见:

  • 尽管RAM使用量增加了1GB,但整个程序在整个执行过程中仅使用5MB。
  • 注释调用
    fread()
    out可以消除内存泄漏。这很奇怪,因为我没有在它附近分配任何东西,这可能会触发内存泄漏
  • 另外,正常读取文件而不是向后读取(=注释调用
    fseeko()
    out),也会消除内存泄漏。这是非常奇怪的部分
  • 进一步资料

  • 以下内容没有帮助:
  • 检查
    fread()
    -的结果不会产生任何异常
  • 切换到正常、32位
    fseek
    ftell
  • 执行类似于
    setbuf(fileHandle,NULL)
    的操作
  • 执行类似于
    setvbuf(fileHandle,NULL,_-IONBF,*任意整数*)
    的操作
  • 通过cygwin和mingw在windows7上用g++4.5.3编译;没有任何优化,只需
    g++test.cpp-o test
    。两者都表现出这种行为
  • 测试中使用的文件长度为4GB,全是零
  • 图表中的奇怪停顿可以用某种暂时的I/O挂起来解释,与这个问题无关。
  • 最后,如果我将阅读包装在无限循环中。。。内存使用在第一次迭代后停止增加


  • 我认为这与某种内部缓存的建立有关,直到它被整个文件填满。它在幕后到底是如何运作的?如何以可移植的方式防止这种情况发生???

    我认为,这与其说是程序的问题,不如说是操作系统问题(甚至是操作系统资源使用报告问题)。当然,它只使用5 MB内存:1 MB用于自身(libs、stack等),4 MB用于缓冲区。每当您执行fread()时,操作系统似乎会将文件的一部分“绑定”到您的进程,并且似乎会以不同的速度释放它。由于计算机上的内存使用率较低,这不是问题:操作系统只是将已经读取的数据“挂起”的时间比必要的时间长,可能是假设应用程序可能很快再次读取数据,然后就不必再次进行绑定


    如果内存压力更大,操作系统很可能会更快地解除内存绑定,因此内存使用历史记录上的跳跃会更小。

    我也遇到了完全相同的问题,尽管是在Java中,但在这种情况下并不重要。我通过一次读更大的文章来解决这个问题。我也读4Mb大小的块,但当我把它增加到100-200MB时,问题就消失了。也许这对你也有好处。我使用的是Windows 7。

    您尝试过通过valgrind运行它吗?(或任何其他内存调试器)首先,这不好
    const int bufferSize=4*1024*1024
    。。。它应该是
    const int bufferSize=sizeof(int)*1024*1024
    @jacobbollack:4*1024*1024部分只有4MB。它可以是任何内容,例如8KB。它与整数的大小无关…@Jocke:使用内存调试器可能是无用的-问题是,在我使用的任何资源监视器中,整个程序都使用5MB。我没有看到内存泄漏。在程序执行过程中,我看到大量内存使用,但这与内存泄漏完全不同。在我看来,向后读取文件是一项简单的任务。为什么操作系统(Windows7)会迭代地缓存整个4GB文件,直到内存耗尽,它不得不求助于页面文件,然后。。。?(它会这样做,取决于我的缓冲区大小…)你确定Win7正在忙着分页吗?或者,它只是忙于重新读取您的4G文件,而该文件(部分)由于笨拙而从文件缓存中抛出?因为您正在反向读取,读取文件的磁盘活动听起来可能与密集分页非常相似。磁盘活动本身不会污染RAM,是吗?在Win8上证实了同样的行为。谁说“RAM被污染了”?仅仅因为操作系统锁定了一个页面(并因此将其报告为“已使用”),并不意味着它是脏的。当我使用4MB缓冲区读取某些内容时,我的整个系统会冻结。这太疯狂了。我不想要它。我不需要