(正确的代码在'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失败,则打印出错误。
更新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 r-x-- test
0000000000600000 4 4 4 rw--- test
00007f1cc941e000 1640 280 0 r-x-- 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 r-x-- 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 r-x-- [ anon ]
ffffffffff600000 4 0 0 r-x-- [ anon ]
---------------- ------ ------ ------
total kB 4040 476 80
pmap -x 5618
5618: ./test
Address Kbytes RSS Dirty Mode Mapping
0000000000400000 4 4 0 r-x-- test
0000000000600000 4 4 4 rw--- test
00007f1cc941e000 1640 280 0 r-x-- 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 r-x-- 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 r-x-- [ anon ]
ffffffffff600000 4 0 0 r-x-- [ 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
除pid外,其他输出与'Update 3'相同(仍然失败)。
更新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给出:向mmap添加MAP_NORESERVE标志解决了这个问题。详细的原因在于caf的回答。非常感谢咖啡馆,所有这些都给予了一些帮助!
答案 0 :(得分:8)
如果您实际上没有配置超过8G的交换,则该大型映射可能会失败。
您可以将MAP_NORESERVE
标记添加到mmap()
,告诉它不要为前映射保留任何交换空间。
答案 1 :(得分:3)
有多少物理内存? Linux有两种不同的地址空间分配模式:写入时的内存分配(即过度使用模式)或地址空间分配时的内存分配。您可以通过读取procfs中的两个文件进行检查:
cat /proc/sys/vm/overcommit_memory
cat /proc/sys/vm/overcommit_ratio
如果overcommit_memory 不是 0,则每个地址空间分配必须由物理内存(RAM +交换空间)支持,如果overcommit_memory 0,则内存过载,即内核将很乐意分发地址空间,但只有在将数据写入分配的地址空间时才会分配内存。然后,内存不会分配给完整的保留地址空间,而是仅针对那些被触摸的页面。这有点像预订机票:航空公司通常卖的票数多于飞机上的座位数,预计并非所有预订的乘客都会出现。现在您可能想知道,如果所有程序都使用了整个空间会发生什么......那么一些令人讨厌的事情就会爆发:Linux Out Of Memory Killer会对您的系统造成严重破坏,很可能会杀死您最需要的进程,因为这是一种神秘的启发式方法。
overcommit_ratio告诉内核
在过度使用模式下物理内存可能被过度使用的比例,即可以分配多少地址空间,而不是物理内存。
在非过度使用模式下要保留多少备用内存
因此,过度使用模式可能会在系统之间产生差异。
答案 2 :(得分:2)
只需在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);
答案 3 :(得分:1)
由于您尝试映射到特定地址,因此当您致电mmap
时,它将取决于您的流程的当前内存布局。满足请求的策略是系统相关的,linux手册页中有一些“提示”。
因此,在第一种情况下,您的流程的虚拟地址空间中没有足够的空间来满足请求,因为在该范围内已经存在另一种映射。
检查这是否与此相关的一个好主意是在您未提供addr
提示时检查您是否成功。
答案 4 :(得分:1)
也许您遇到资源限制?尝试添加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 r-x-- zhiqiang
0000000000600000 0 4 4 r---- zhiqiang
0000000000601000 0 4 4 rw--- zhiqiang
00007f37b3c27000 0 260 0 r-x-- 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 r-x-- 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 r-x-- [ anon ]
ffffffffff600000 0 0 0 r-x-- [ anon ]
---------------- ------ ------ ------
total kB 3912 464 88
pmap -x 23819
23819: ./zhiqiang
Address Kbytes RSS Dirty Mode Mapping
0000000000400000 0 4 0 r-x-- zhiqiang
0000000000600000 0 4 4 r---- zhiqiang
0000000000601000 0 4 4 rw--- zhiqiang
0000000400000000 0 0 0 rw--- [ anon ]
00007f37b3c27000 0 260 0 r-x-- 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 r-x-- 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 r-x-- [ anon ]
ffffffffff600000 0 0 0 r-x-- [ 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.