(正确的代码在'Update 5'中)
我试图映射从0x100000000到0x200000000在这个例子C代码的内存范围:
#include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <sys/mman.h> int main(void) { uint64_t* rr_addr = 0; uint64_t i = 17179869184; printf("\nsizeof(size_t): %llu\n", sizeof(size_t)); printf("(uint64_t)0x100000000: %llx\n", (uint64_t)0x100000000); printf("1L << 33: %llx\n", 1L << 33); rr_addr = mmap((void*)i, (1UL << 33), PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); printf("rr_addr: %p, %llu \n", rr_addr, rr_addr); if (rr_addr == MAP_FAILED) { perror("mmap error"); } return 0; }
在不同的系统上(Linux,gcc),我得到了不同的结果:
结果1:
sizeof(size_t): 8 (uint64_t)0x100000000: 100000000 1L << 33: 200000000 rr_addr: 0xffffffffffffffff, 18446744073709551615 mmap error: Cannot allocate memory
系统信息(Fedora 14):
Linux localhost.localdomain 2.6.35.10-74.fc14.x86_64 #1 SMP Thu Dec 23 16:04:50 UTC 2010 x86_64 x86_64 x86_64 GNU/Linux gcc (GCC) 4.5.1 20100924 (Red Hat 4.5.1-4) glibc: 2.12.90-21
结果2:
sizeof(size_t): 8 (uint64_t)0x100000000: 100000000 1L << 33: 200000000 rr_addr: 0x400000000, 17179869184
系统信息(Fedora 12):
Linux wiles 2.6.32.13 #2 SMP Fri Sep 10 01:29:43 HKT 2010 x86_64 x86_64 x86_64 GNU/Linux gcc (GCC) 4.4.4 20100630 (Red Hat 4.4.4-10) glibc verison: 2.11.2-1
我期待“结果2”。 也许我的代码有问题。
请帮我一下
更新1 :如果mmap失败,errno将被打印出来。
更新3 :将mmap调用更改为以下行之后:
char *cmd[20]; sprintf(cmd, "pmap -x %i", getpid()); printf("%s\n", cmd); system(cmd); rr_addr = mmap((void*)i, (1UL << 33), PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); printf("%s\n", cmd); system(cmd);
结果:
sizeof(size_t): 8 (uint64_t)0x100000000: 100000000 1L << 33: 200000000 pmap -x 5618 5618: ./test Address Kbytes RSS Dirty Mode Mapping 0000000000400000 4 4 0 rx-- test 0000000000600000 4 4 4 rw--- test 00007f1cc941e000 1640 280 0 rx-- libc-2.12.90.so 00007f1cc95b8000 2044 0 0 ----- libc-2.12.90.so 00007f1cc97b7000 16 16 16 r---- libc-2.12.90.so 00007f1cc97bb000 4 4 4 rw--- libc-2.12.90.so 00007f1cc97bc000 24 16 16 rw--- [ anon ] 00007f1cc97c2000 132 108 0 rx-- ld-2.12.90.so 00007f1cc99c6000 12 12 12 rw--- [ anon ] 00007f1cc99e0000 8 8 8 rw--- [ anon ] 00007f1cc99e2000 4 4 4 r---- ld-2.12.90.so 00007f1cc99e3000 4 4 4 rw--- ld-2.12.90.so 00007f1cc99e4000 4 4 4 rw--- [ anon ] 00007fffa0da8000 132 8 8 rw--- [ stack ] 00007fffa0dff000 4 4 0 rx-- [ anon ] ffffffffff600000 4 0 0 rx-- [ anon ] ---------------- ------ ------ ------ total kB 4040 476 80 pmap -x 5618 5618: ./test Address Kbytes RSS Dirty Mode Mapping 0000000000400000 4 4 0 rx-- test 0000000000600000 4 4 4 rw--- test 00007f1cc941e000 1640 280 0 rx-- libc-2.12.90.so 00007f1cc95b8000 2044 0 0 ----- libc-2.12.90.so 00007f1cc97b7000 16 16 16 r---- libc-2.12.90.so 00007f1cc97bb000 4 4 4 rw--- libc-2.12.90.so 00007f1cc97bc000 24 16 16 rw--- [ anon ] 00007f1cc97c2000 132 108 0 rx-- ld-2.12.90.so 00007f1cc99c6000 12 12 12 rw--- [ anon ] 00007f1cc99e0000 8 8 8 rw--- [ anon ] 00007f1cc99e2000 4 4 4 r---- ld-2.12.90.so 00007f1cc99e3000 4 4 4 rw--- ld-2.12.90.so 00007f1cc99e4000 4 4 4 rw--- [ anon ] 00007fffa0da8000 132 8 8 rw--- [ stack ] 00007fffa0dff000 4 4 0 rx-- [ anon ] ffffffffff600000 4 0 0 rx-- [ anon ] ---------------- ------ ------ ------ total kB 4040 476 80 rr_addr: 0xffffffffffffffff, 18446744073709551615 mmap error: Cannot allocate memory
更新4 :添加“system(”ulimit -m -v“);” 就在调用mmap之前:ulimit的输出是:
max memory size (kbytes, -m) unlimited virtual memory (kbytes, -v) unlimited
其他输出与“更新3”(仍然失败)相同,除了PID。
更新5 :在两个系统上工作的更新的代码:
#include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <sys/mman.h> int main(void) { uint64_t* rr_addr = 0; uint64_t i = 17179869184; uint64_t len = 0; char cmd[20]; printf("\nsizeof(size_t): %llu\n", sizeof(size_t)); len = (1UL << 32); printf("len: %llx\n", len); snprintf(cmd, sizeof cmd, "pmap -x %i", getpid()); printf("%s\n", cmd); system(cmd); system("ulimit -m -v"); rr_addr = mmap((void*)i, len, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE|MAP_NORESERVE, -1, 0); printf("%s\n", cmd); system(cmd); printf("rr_addr: %p, %llu \n", rr_addr, rr_addr); if (rr_addr == MAP_FAILED) { perror("mmap error"); } return 0; }
@caf给出了正确的答案:将MAP_NORESERVE标志添加到mmap解决了这个问题。 详细的原因在咖啡的答案。 感谢很多咖啡,所有这些给予善意的帮助!
如果实际上没有配置大于8G的交换,那么这个大的映射可能会失败。
您可以将MAP_NORESERVE
标志添加到mmap()
以告诉它不要为MAP_NORESERVE
映射保留任何交换空间。
有多少物理内存? Linux有两种不同的地址空间分配模式:写入时的内存分配(即过度使用模式)或地址空间分配时的内存分配。 您可以通过阅读procfs中的两个文件来检查:
cat /proc/sys/vm/overcommit_memory cat /proc/sys/vm/overcommit_ratio
如果overcommit_memory 不是 0,那么每个地址空间分配必须由物理内存(RAM +交换空间)支持,如果overcommit_memory 为 0,则内存被过度占用,即内核将愉快地分配地址空间,但内存将是唯一的如果数据写入分配的地址空间则分配。 然后内存不会被分配给完整的保留地址空间,而只能分配给那些被触摸的页面。 这就像预订机票一样:航空公司通常会出售比机上有座位更多的机票,预计并非所有预订的乘客都会出现。 现在你可能会想,如果所有的程序都利用了整个空间会发生什么……那么一些讨厌的事情就会发生:Linux内存不足杀手会对你的系统造成严重破坏,很可能会导致你最需要的进程被终止这是神秘的启发式。
overcommit_ratio告诉内核
在过度使用模式下,物理内存可能被过度占用,即有多少地址空间可能被分配出来,而不是物理内存。
在非过度使用模式下需要保留多少内存
所以也许过度使用模式只是不同的系统之间。
刚刚在Fedora 13上运行你的代码,并产生结果2。
当mmap()返回MAP_FAILED(-1)时,检查errno。 您也可以在mmap调用之前和之后粘贴以下行,以查看在4GB区域的进程的虚拟地址空间中是否有空间:
system("pmap -x $$");
更新:上面实际上是打印子进程的地图。 正确的代码:
char buf[0x100]; snprintf(buf, sizeof buf, "pmap -x %u", (unsigned)getpid()); system(buf);
由于您尝试映射到特定的地址,因此在调用mmap
时,将取决于当前的进程内存布局。 请求的地址所遵循的策略是依赖于系统的,linux手册页中提到了一些“提示”。
因此,也许在第一种情况下,在进程的虚拟地址空间中没有足够的空间来满足请求,因为在该范围内已经有另一个映射。
检查这是否与此相关的一个好主意是在不提供addr
提示时检查是否成功。
也许你遇到了资源限制? 尝试添加system("ulimit -m -v");
打印出可以分配的内存和地址空间量。
编辑 :好吧,我没有想法。 抱歉。 清理代码中的错误和警告之后,我有这个来源:
#include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <sys/mman.h> int main(void) { uint64_t* rr_addr = 0; uint64_t i = 17179869184; printf("\nsizeof(size_t): %lu\n", sizeof(size_t)); printf("(uint64_t)0x100000000: %lx\n", (uint64_t)0x100000000); printf("1L << 33: %lx\n", 1L << 33); char cmd[20]; sprintf(cmd, "pmap -x %i", getpid()); printf("%s\n", cmd); system(cmd); rr_addr = mmap((void*)i, (1UL << 33), PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); printf("%s\n", cmd); system(cmd); printf("rr_addr: %p, %lu \n", rr_addr, rr_addr); if (rr_addr == MAP_FAILED) { perror("mmap error"); } return 0; }
和这个输出:
sizeof(size_t): 8 (uint64_t)0x100000000: 100000000 1L << 33: 200000000 pmap -x 23819 23819: ./zhiqiang Address Kbytes RSS Dirty Mode Mapping 0000000000400000 0 4 0 rx-- zhiqiang 0000000000600000 0 4 4 r---- zhiqiang 0000000000601000 0 4 4 rw--- zhiqiang 00007f37b3c27000 0 260 0 rx-- libc-2.12.1.so 00007f37b3da1000 0 0 0 ----- libc-2.12.1.so 00007f37b3fa0000 0 16 16 r---- libc-2.12.1.so 00007f37b3fa4000 0 4 4 rw--- libc-2.12.1.so 00007f37b3fa5000 0 12 12 rw--- [ anon ] 00007f37b3faa000 0 108 0 rx-- ld-2.12.1.so 00007f37b41aa000 0 12 12 rw--- [ anon ] 00007f37b41c7000 0 12 12 rw--- [ anon ] 00007f37b41ca000 0 4 4 r---- ld-2.12.1.so 00007f37b41cb000 0 4 4 rw--- ld-2.12.1.so 00007f37b41cc000 0 4 4 rw--- [ anon ] 00007fff70cf8000 0 12 12 rw--- [ stack ] 00007fff70dff000 0 4 0 rx-- [ anon ] ffffffffff600000 0 0 0 rx-- [ anon ] ---------------- ------ ------ ------ total kB 3912 464 88 pmap -x 23819 23819: ./zhiqiang Address Kbytes RSS Dirty Mode Mapping 0000000000400000 0 4 0 rx-- zhiqiang 0000000000600000 0 4 4 r---- zhiqiang 0000000000601000 0 4 4 rw--- zhiqiang 0000000400000000 0 0 0 rw--- [ anon ] 00007f37b3c27000 0 260 0 rx-- libc-2.12.1.so 00007f37b3da1000 0 0 0 ----- libc-2.12.1.so 00007f37b3fa0000 0 16 16 r---- libc-2.12.1.so 00007f37b3fa4000 0 4 4 rw--- libc-2.12.1.so 00007f37b3fa5000 0 12 12 rw--- [ anon ] 00007f37b3faa000 0 108 0 rx-- ld-2.12.1.so 00007f37b41aa000 0 12 12 rw--- [ anon ] 00007f37b41c7000 0 12 12 rw--- [ anon ] 00007f37b41ca000 0 4 4 r---- ld-2.12.1.so 00007f37b41cb000 0 4 4 rw--- ld-2.12.1.so 00007f37b41cc000 0 4 4 rw--- [ anon ] 00007fff70cf8000 0 12 12 rw--- [ stack ] 00007fff70dff000 0 4 0 rx-- [ anon ] ffffffffff600000 0 0 0 rx-- [ anon ] ---------------- ------ ------ ------ total kB 8392520 464 88 rr_addr: 0x400000000, 17179869184
和我的系统的细节:
Linux haig 2.6.35-24-generic #42-Ubuntu SMP Thu Dec 2 02:41:37 UTC 2010 x86_64 GNU/Linux gcc version 4.4.5 (Ubuntu/Linaro 4.4.4-14ubuntu5) GNU C Library (Ubuntu EGLIBC 2.12.1-0ubuntu10.1) stable release version 2.12.1, by Roland McGrath et al.