You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用mmap优化大文件处理的内存占用问题求助

问题原因

你当前的代码一次性将整个20GB文件映射到内存,虽然mmap本身不会立即分配物理内存,但当你顺序遍历所有数据时,内核会把每个访问过的页面加载到物理内存并缓存起来,最终导致整个文件都驻留在内存中,占用20GB空间。

解决方案

要把内存消耗控制在1GB左右,核心思路是分块映射文件:每次只映射文件中1GB左右的片段,处理完该片段后立即解除映射,让内核回收这部分内存,再处理下一块。

需要注意几个关键点:

  • 映射的偏移和长度必须对齐到系统页大小(通常是4KB或8KB),可通过sysconf(_SC_PAGESIZE)获取页大小。
  • 文件总大小可能不是1GB的整数倍,最后一块需按实际剩余大小处理。
  • 每块处理完成后必须调用munmap释放映射区域,避免内存泄漏。
修改后的示例代码
#include <iostream>
#include <string>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <cstdlib>

int main() {
    std::string srcPath = "srcList.bin";
    int srcFd = open(srcPath.c_str(), O_RDONLY);
    if (srcFd == -1) {
        perror("open");
        return EXIT_FAILURE;
    }

    struct stat sb;
    if (fstat(srcFd, &sb) == -1) {
        perror("fstat");
        close(srcFd);
        return EXIT_FAILURE;
    }
    off_t total_bytes = sb.st_size;
    const size_t page_size = sysconf(_SC_PAGESIZE);
    // 设置每块映射大小为1GB,并对齐到页大小
    const size_t block_bytes = 1024 * 1024 * 1024;
    const size_t aligned_block_bytes = (block_bytes + page_size - 1) & ~(page_size - 1);

    for (off_t offset = 0; offset < total_bytes; offset += aligned_block_bytes) {
        // 计算当前块的实际大小(最后一块可能小于1GB)
        size_t current_block_bytes = std::min(static_cast<size_t>(total_bytes - offset), aligned_block_bytes);
        // 映射当前块
        int64_t* block_addr = static_cast<int64_t*>(mmap(nullptr, current_block_bytes, PROT_READ, MAP_SHARED, srcFd, offset));
        if (block_addr == MAP_FAILED) {
            perror("mmap");
            close(srcFd);
            return EXIT_FAILURE;
        }

        // 计算当前块的int64_t元素数量(每个元素占8字节)
        size_t element_count = current_block_bytes / sizeof(int64_t);
        // 处理当前块的元素
        for (size_t i = 0; i < element_count; ++i) {
            int64_t tmp = block_addr[i];
            // do something
        }

        // 解除当前块的映射,释放内存
        if (munmap(block_addr, current_block_bytes) == -1) {
            perror("munmap");
            close(srcFd);
            return EXIT_FAILURE;
        }
    }

    close(srcFd);
    return EXIT_SUCCESS;
}
额外说明
  • 映射模式选择:如果只是读取文件,MAP_SHARED和MAP_PRIVATE都可以,只读场景下两者差异不大,核心还是分块映射逻辑。
  • 页对齐必要性:mmap要求映射的偏移和长度必须是页大小的整数倍,否则会触发错误,代码中已对块大小做了对齐处理。
  • 原代码修正:你原本的循环条件i < srcLength是错误的——srcLength是文件字节数,而srcAddr[i]是按int64_t元素索引,正确逻辑应该是按元素数量遍历,修改后的代码已修复该问题。

内容的提问来源于stack exchange,提问作者YA xiang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 17:42:22