在linux下:
#free -m total used free shared buffers cached Mem: 1995 1460 534 0 68 432 -/+ buffers/cache: 959 1035 Swap: 2055 743 1311 # cat /proc/sys/vm/overcommit_memory 0 #cat /proc/sys/vm/overcommit_ratio 50
测试代码1:
#define PER_PAGE_SIZE 4096
#define MMAP(fd,offset) mmap (NULL,PER_PAGE_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_NORESERVE,fd,offset)
int main(){
int j = 0;
int fd = open("dat.tmp",O_RDWR);
for(int i = 131071 ; i >= 0; i--){
++j;
void* r = MMAP(fd,i*4096);
if(r == MAP_FAILED){
printf("%d,%m\n",j);
break;
}
}
cout << "done " << j << endl;
sleep(5);
}
############## error message : # ./a.out 65513,Cannot allocate memory done 65513 ... #################
测试代码2:
#define PER_PAGE_SIZE 4096
#define MMAP(fd,offset) mmap (NULL,PER_PAGE_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_NORESERVE,fd,offset)
int main(){
int j = 0;
int fd = open("dat.tmp",O_RDWR);
for(int i = 0 ; i <= 131071; i++){
++j;
void* r = MMAP(fd,i*4096);
if(r == MAP_FAILED){
printf("%d,%m\n",j);
break;
}
}
cout << "done " << j << endl;
sleep(5);
}
这是有效的,所以,为什么???????????
答案 0 :(得分:4)
这是我的猜测。我猜第二个程序只是扩展了一个描述单个映射的内部数据结构,以包含一个页面。第一个可以做到这一点,但它必须向后延伸,我打赌合并映射的特殊情况代码甚至不检查。
它停在65513这一事实非常具有启发性。将有一些映射用于共享库等的映射,因此您可以使用少于65536个映射。 65536是许多内核人员用于数据结构的大小。
我建议查看/proc/<pid>/maps
并查看程序休眠时每种情况下列出的地图数量。为方便起见,您可能希望在打印出“完成”消息时打印出getpid()
的结果。
我不能直接复制你的问题,所以在我的系统上似乎已经正确处理了相反的情况。我系统上uname -a
的输出是:
Linux a_hostname.somewhere 2.6.35.11-83.fc14.x86_64 #1 SMP Mon Feb 7 07:06:44 UTC 2011 x86_64 x86_64 x86_64 GNU/Linux
但是这个程序确实会复制你的问题:
#include <iostream>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#define PER_PAGE_SIZE 4096
#define MMAP(fd,offset) mmap (NULL,PER_PAGE_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_NORESERVE,fd,offset)
int main()
{
using ::std::cout;
using ::std::endl;
int j = 0;
int fd = open("dat.tmp",O_RDWR);
char catcmd[] = "cat /proc/99999/maps_padding";
for(int i = 131071 ; i >= 0; i-=2){
++j;
void* r = MMAP(fd,i*4096);
if(r == MAP_FAILED){
cout << j << ", " << strerror(errno) << '\n';
break;
}
}
::std::snprintf(catcmd, sizeof(catcmd), "cat /proc/%d/maps", getpid());
cout.flush();
::std::system(catcmd);
cout << "done " << j << endl;
sleep(5);
}
正如您所看到的,如果您向后跳过2,问题仍然会发生。调用cat /proc/<pid>/maps
时system
的输出显示确实存在数千张单独的地图。
如果我停止跳过2并且只是向后退,我最终得到2张地图,一张较大,另一张不太大。如果可以,内核会将相邻的地图合并为一个地图。
作为进一步确凿的证据证明你的问题与我所描述的一样,就是nice discussion of /proc/sys/vm/max_map_count
。设置该变量可以更改有多少个地图,默认设置为65530。