【问题标题】:Why mmap a 4GB file on 32-bit armv7l succeeded?为什么在 32 位 armv7l 上 mmap 4GB 文件成功?
【发布时间】:2016-05-24 09:18:02
【问题描述】:

我从mmap(2) 手册页和搜索结果中得到的印象是,mmap 仅限于系统的可用地址空间,减去系统保留的地址空间。所以在 32 位 armv7l 上,我假设它大约是 3GB = (4GB - 1GB)。

但似乎我实际上可以mmap 一个 5 GB 的文件而没有任何问题:

int main(int argc, char** argv) {
        // stats
        char * path = argv[1];
        struct stat sb; 
        stat(path, &sb);
        std::cout << "File size: " << sb.st_size << std::endl;  

        // open
        int fd = open(path, O_RDONLY, S_IRWXU);
        std::cout << "File descriptor: " << fd << std::endl;
        int i;
        for (i =0; i<10; ++i){
                void *pa = mmap(
                        nullptr, sb.st_size, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, fd, 0);
                std::cout << "PA: " << pa  
                        << ", MAP_FAILED: " 
                        << (pa == MAP_FAILED) << ", Status: " 
                        << strerror(errno) << std::endl;
        }   
}

使用-D_FILE_OFFSET_BITS=64 标志编译:

g++  -D_FILE_OFFSET_BITS=64 test.cc

结果产生:

File size: 5045966585
File descriptor: 3
PA: 0x89f80000, MAP_FAILED: 0, Status: Success
PA: 0x5d34a000, MAP_FAILED: 0, Status: Success
PA: 0x30714000, MAP_FAILED: 0, Status: Success
PA: 0x3ade000, MAP_FAILED: 0, Status: Success
PA: 0xffffffff, MAP_FAILED: 1, Status: Cannot allocate memory
PA: 0xffffffff, MAP_FAILED: 1, Status: Cannot allocate memory
PA: 0xffffffff, MAP_FAILED: 1, Status: Cannot allocate memory
PA: 0xffffffff, MAP_FAILED: 1, Status: Cannot allocate memory
PA: 0xffffffff, MAP_FAILED: 1, Status: Cannot allocate memory
PA: 0xffffffff, MAP_FAILED: 1, Status: Cannot allocate memory

从结果来看,mmap 成功了 4 次,然后才真正遇到麻烦。但它不应该成功,因为该文件约为 5GB。

我的问题是:

  1. mmap 会出现这种行为吗?
  2. 如果不是,我哪里做错了?

编辑:

使用物理地址扩展 (PAE),32 位系统可以添加超过 2^32 字节(如果可用)的地址。

此 CPU 不支持 PAE

$> cat /proc/cpuinfo

Processor       : ARMv7 Processor rev 4 (v7l)
processor       : 0
BogoMIPS        : 1436.46

processor       : 1
BogoMIPS        : 1436.46

Features        : swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt 
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x0
CPU part        : 0xc07
CPU revision    : 4

Hardware        : sun7i
Revision        : 0000
Serial          : 09c11b9d52544848804857831651664b

【问题讨论】:

  • 与您的问题无关,仅供参考,但在使用printf 格式"%p" 打印指针时,参数应该void *,因此不需要强制转换.还有一个 output operator overload 采用 void * 用于打印指针,因此根本不需要旧的 C printf 函数。
  • mmap()的函数原型是什么?如果第二个参数只有 32 位,则您的 64 位 sb.st_size 可能会被截断。
  • 是的,溢出只分配了 716 MB。
  • @hetepeperfan 在 ARM 中是 LPAE。但这就是操作系统识别内存的方式。每个进程的地址空间仍然限制为 32 位指针,因此需要 2-4GB 的 RAM
  • @c3V6a2Vy,第二个参数是size_tmmaplast 参数是 off_t

标签: c++ memory mmap


【解决方案1】:

PAE 无关紧要。这与访问大量物理内存无关。

问题在于您的 mmap 函数采用 32 位值作为映射大小。因此,您的 64 位大小会被截断,您实际上分配的虚拟内存不到 1 GB。

【讨论】:

    猜你喜欢
    • 2014-09-28
    • 2017-02-03
    • 2013-03-25
    • 1970-01-01
    • 2017-06-05
    • 2012-12-21
    • 1970-01-01
    • 2018-04-15
    • 1970-01-01
    相关资源
    最近更新 更多