mmap 只适用于小文件?

mmap only works on small files?

我正在尝试将文件从本地磁盘映射到内存中,以便我的程序可以访问文件内容。当对文件(大小不到 100kB)调用 mmap 时,我在调试器中查看从 mmap 返回的地址开始的内存,内存内容与文件内容不匹配(均以十六进制查看)。这是不是字节交换问题。只有内存中的前2个字节与实际文件匹配,其余内容不匹配。

当我在一个包含字符串的小文件上重复相同的操作(例如:"hello world")时,调试器中显示的内存与文件的内容完全匹配(再次以十六进制显示)。

我尝试使用 MAP_PRIVATE 而不是 MAP_SHARED 但结果相同。我怎样才能让它与我的大文件一起使用?

我正在 Ubuntu 17.10 中使用 Eclipse 4.7.2 + CDT 并使用 GDB 进行调试。

#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string>
#include <unistd.h>
#include <sys/mman.h>

int main()
{
    void* MapAddr = NULL;
    char* pData = NULL;
    struct stat FileProps;
    int FileDes = 0;
    const char* fileNameAndPath = "/home/Test/testfile.txt";

    FileDes = open(fileNameAndPath, O_RDWR);

    if (FileDes != -1)
    {
        if (fstat(FileDes, &FileProps) == 0)
        {
            MapAddr = mmap(NULL, FileProps.st_size, (PROT_READ | PROT_WRITE), MAP_SHARED, FileDes, 0);
            if (MapAddr == (void*) -1)
            {
                std::cout << "init: mmap failed" << std::endl;
                return 0;
            }
        }
    }
    pData = (char*) MapAddr;
    std::cout << pData << std::endl;
    return 0;
}

13:10:42 **** 为项目 mmapTest 构建配置调试 **** 让所有 构建文件:../src/mmapTest.cpp 调用:GCC C++ 编译器 g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/mmapTest.d" -MT"src/mmapTest.o" -o "src/mmapTest.o" "../src/mmapTest.cpp “ 完成建筑:../src/mmapTest.cpp

构建目标:mmapTest 调用:GCC C++ 链接器 g++ -o "mmapTest" ./src/mmapTest.o
完成构建目标:mmapTest

13:10:46 构建完成(耗时 4s.438ms)

mmap() 实际上并没有将整个文件读入内存,也没有实际分配文件大小的 RAM 量。它只是分配虚拟地址 space 大到足以 "fit" 其中的文件。

它通过使用页面错误来工作,当您尝试读取文件的某些区域时,将分配实际的 RAM(或重用一些其他页面)并将一定数量的页面的数据从文件读入内存。

你几乎不可能用 mmap() 将整个文件加载到 ram 中。但是你的程序应该可以工作,无论何时你尝试读取或写入数据(从程序,不是从调试器)一切都会正常工作。


而且,是的,最重要的是,mmap() 的工作方式与 CreateFileMapping() 相同,因此您应该可以移植代码。

我确定内存内容(在 GDB 调试器中查看)与实际文件内容不匹配的原因,在 mmap() 之后 运行,是因为我映射的文件不是 ANSI-encoded。因此,调试器显示了 Linux 认为应该的正确数据。以 ANSI 格式保存文件(在 textpad 中)后,Linux 中查看的文件二进制内容与 Windows 中查看的二进制内容相同。无需更改代码。问题出在被映射的文件上。与其中一条评论相反,GDB 调试器能够在 mmap() 返回的地址处使用内存查看器显示所有映射文件数据 - 我已经确认了最大 100KB 的文件。