我有一个基本上可以做到这一点的程序:
- 打开一些二进制文件
- 向后读取文件(向后,我的意思是它在 EOF 附近开始,并在文件开头结束读取,即“从右到左”读取文件),使用 4MB 块
- 关闭文件
我的问题是:为什么内存消耗如下所示,即使我附加的代码中没有明显的内存泄漏?
以下是为获取上图而运行的程序的源代码:
#include <stdio.h>
#include <string.h>
int main(void)
{
//allocate stuff
const int bufferSize = 4*1024*1024;
FILE *fileHandle = fopen("./input.txt", "rb");
if (!fileHandle)
{
fprintf(stderr, "No file for you\n");
return 1;
}
unsigned char *buffer = new unsigned char[bufferSize];
if (!buffer)
{
fprintf(stderr, "No buffer for you\n");
return 1;
}
//get file size. file can be BIG, hence the fseeko() and ftello()
//instead of fseek() and ftell().
fseeko(fileHandle, 0, SEEK_END);
off_t totalSize = ftello(fileHandle);
fseeko(fileHandle, 0, SEEK_SET);
//read the file... in reverse order. This is important.
for (off_t pos = totalSize - bufferSize, j = 0;
pos >= 0;
pos -= bufferSize, j ++)
{
if (j % 10 == 0)
{
fprintf(stderr,
"reading like crazy: %lld / %lld\n",
pos, totalSize);
}
/*
* below is the heart of the problem. see notes below
*/
//seek to desired position
fseeko(fileHandle, pos, SEEK_SET);
//read the chunk
fread(buffer, sizeof(unsigned char), bufferSize, fileHandle);
}
fclose(fileHandle);
delete []buffer;
}
我也有以下观察:
- 尽管 RAM 使用量增加了 1GB,但整个程序在整个执行过程中只使用了 5MB。
- 注释调用
fread()
out使内存泄漏消失。这很奇怪,因为我没有在它附近分配任何东西,这可能会触发内存泄漏...... - 此外,正常读取文件而不是向后读取(= 注释调用
fseeko()
),也会使内存泄漏消失。这是超奇怪的部分。
更多信息...
- 以下没有帮助:
- 检查
fread()
- 的结果没有任何异常。 - 切换到普通、32 位
fseek
和ftell
. - 做类似的事情
setbuf(fileHandle, NULL)
。 - 做类似的事情
setvbuf(fileHandle, NULL, _IONBF, *any integer*)
。
- 检查
- 通过 cygwin 和 mingw 在 Windows 7 上使用 g++ 4.5.3 编译;没有任何优化,只是
g++ test.cpp -o test
. 两者都存在这种行为。 - 测试中使用的文件长 4GB,全是零。
- 图表中间的奇怪停顿可以用某种与这个问题无关的临时 I/O 挂断来解释。
- 最后,如果我将阅读包装在无限循环中......第一次迭代后内存使用量停止增加。
我认为这与某种内部缓存的建立有关,直到它被整个文件填满。它在幕后是如何运作的?我怎样才能以便携的方式防止这种情况发生?