C++ mmap仅适用于小文件?

C++ mmap仅适用于小文件?,c++,linux,memory,mmap,C++,Linux,Memory,Mmap,我正在尝试将一个文件从本地磁盘映射到内存中,以便我的程序可以访问文件内容。当对大小略小于100kB的文件调用mmap时,我会从mmap返回的地址开始查看调试器中的内存,并且内存内容与以十六进制查看的文件内容不匹配。这不是字节交换问题。只有内存中的前2个字节与实际文件匹配,其余内容不匹配 当我在一个包含字符串ex:hello world的小文件上重复同样的操作时,那么在调试器中查看的内存与再次以十六进制查看的文件内容完全匹配 我尝试使用MAP_PRIVATE而不是MAP_SHARED,但结果相同。

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

当我在一个包含字符串ex:hello world的小文件上重复同样的操作时,那么在调试器中查看的内存与再次以十六进制查看的文件内容完全匹配

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

我在使用Eclipse4.7.2+CDT的Ubuntu17.10中工作,并使用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-MFsrc/mmapTest.d-MTsrc/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构建完成。438ms

mmap实际上不会将整个文件读取到内存中,也不会实际分配文件大小和内存量。它只分配足够大的虚拟地址空间来容纳其中的文件

它的工作原理是使用页面错误,当您尝试读取文件的某个区域时,实际的RAM将被分配,或者重复使用一些其他页面,并将一定数量的页面数据从文件读取到内存中

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


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

我确定,在运行mmap后,GDB调试器中查看的内存内容与实际文件内容不匹配的原因是,我映射的文件不是ANSI编码的。因此,调试器显示了Linux认为应该显示的正确数据。将文件保存为ANSI格式的textpad后,在Linux中查看的文件的二进制内容与在Windows中查看的二进制内容相同。不需要更改代码。问题在于正在映射的文件。与其中一条注释相反,GDB调试器能够使用内存查看器在mmap返回的地址显示所有映射的文件数据-我已经确认了100KB以下的文件的这一点。

我想您知道该程序使用了非标准功能。是否有某种原因使您希望将文件读入映射内存而不是从堆中读入该内存?做后者很容易,而且可以移植。感谢您提供了一个可编译的代码示例。你能展示一下你是如何重现这个问题的吗?但是这个程序能工作吗?nmap是通过分页工作的,调试器可能会也可能不会强制它。JD-mmap是非标准的,还是我正在做的其他事情?我正在尝试将Windows函数CreateFileMapping移植到Linux。我的目标是将数据从文件中取出,映射到内存中,然后将内存映射到结构指针。有更好的方法吗?@JiveDadson它在问题中描述的平台上编译。我不明白你想表达什么样的观点,或者为什么在这种情况下它是有用的。我想知道GDB如何在不导致页面错误的情况下加载内存?谢谢你的快速响应BJovke。让我确认它在不使用调试器的情况下工作。我将尝试将一些结构或内容映射到文件内容,并尝试打印它们。所有调试器都使用专门为调试而创建的特殊CPU指令。最有可能的是,调试器有一个选项,它不会导致页面错误,也不会因运行调试器而导致任何其他副作用。这个想法是为了模拟程序的实际工作环境。我认为在Linux程序的调试器中看到意外内存的问题在于,我正在映射一个在Windows应用程序中使用的文件,并且很可能是为Windows编码的。这听起来像是一种可能的解释吗?i、 e:在Linux中使用mmap映射在Windows中编码的文件,并看到错误的内容。在Windows调试器中,内存与文件内容完全匹配。抱歉,我对不同OSs UTF8之间的文件编码知之甚少。CreateFileMapping最初可能会将文件的大部分加载到RAM中,这完全取决于它是如何在内部实现的。如果初始缓冲区大于文件,则读取整个文件。对你来说,这无关紧要,当你试图读取数据时,你总是会得到你的内容。不要试图依赖mmap和CreateFileMapping的内部工作,它们都是 向您保证您的程序将按预期工作。