我正在尝试使用
mmap
读取大文件并计算其中的一些数据。然而,我注意到在计算过程中,整个文件似乎仍在加载到内存中(大约20GB),这让我感到困惑。我该怎么做才能让我的操作只消耗1GB左右的内存?
int main{
std::string srcPath = "srcList.bin";
int srcFd = open(srcPath.c_str(), O_RDONLY);
struct stat sb;
if (fstat(srcFd, &sb) == -1) {
perror("fstat");close(srcFd);
}
off_t srcLength = sb.st_size;
int64_t* srcAddr = static_cast<int64_t*>(mmap(nullptr, srcLength, PROT_READ, MAP_SHARED, srcFd, 0));
for (int i = 0 ; i <srcLength;i++ ){
int64_t tmp = srcAddr[i];
// do something
}
}
整个文件“似乎”被加载到内存中是由于您在循环中访问内存映射文件的方式所致,
mmap
将整个文件映射到内存中,但不一定将整个文件加载到内存中立即内存。
在您使用的循环中,您使用
srcAddr[i]
一次访问内存映射文件的元素,当您这样做时,操作系统会将文件的一页加载到内存中,大约为 1。 ~4Kb。如果按顺序访问所有元素,操作系统将根据需要将页面加载到内存中。但是,如果您使用的循环涉及整个文件的随机访问,则最终可能会将许多页面加载到内存中,这看起来就像加载整个文件。
将使用的内存量限制为大约。 1Gb,您可以通过一次仅映射文件的一部分并以块的形式处理它来控制内存映射区域的大小。比如:
off_t chunkSize = 1LL << 30; // 1Gb size
for (off_t offset = 0; offset < srcLength; offset += chunkSize) {
off_t mapSize = std::min(chunkSize, srcLength - offset);
int64_t* srcAddr = static_cast<int64_t*>(mmap(nullptr, mapSize, PROT_READ, MAP_SHARED, srcFd, offset)); // map the chunk
// Process the chunk
for (off_t i = 0; i < mapSize / sizeof(int64_t); i++) {
int64_t tmp = srcAddr[i];
// here you do something with tmp
}
munmap(srcAddr, mapSize); // unmap the chunk
}