这个问题下面隐含着别的问题:你需要分配多少内存?操作系统给你分配了多少?OOM的基本原因很简单,你申请的内存多于系统可用量。我得说是虚拟内存,因为交换分区也包括在内。
了解OOM
开始了解OOM,首先试试这段会分配大量内存的代码:
引用:#include
#include
#define MEGABYTE 1024*1024
int main(int argc, char *argv[])
{
void *myblock = NULL;
int count = 0;
while (1)
{
myblock = (void *) malloc(MEGABYTE);
if (!myblock) break;
printf(”Currently allocating %d MBn”, ++count);
}
exit(0);
}
编译一下,运行它之后等一会。系统早晚会OOM。然后试试下面这段,分配大量内存并用1写入:
引用:#include
#include
#define MEGABYTE 1024*1024
int main(int argc, char *argv[])
{
void *myblock = NULL;
int count = 0;
while(1)
{
myblock = (void *) malloc(MEGABYTE);
if (!myblock) break;
memset(myblock,1, MEGABYTE);
printf(”Currently allocating %d MBn”,++count);
}
exit(0);
}
发现差别了么?A比B分配了更多内存。而且B被杀掉的更早一些。两个程序都因为没有可用内存而退出。更准确的说,A因为失败的malloc()而优雅的退出了,B是被OOM杀手干掉了。
首先观察分配的内存块数。假设你使用256M内存,888M交换分区(我的情况),B结束时:
Currently allocating 1081 MB
而A结束时:
Currently allocating 3056 MB
A怎么弄来的另外1975M?我骗人?没有!如果你仔细看,你会发现B用1填满得到的内存,而A几乎不拿他们干什么。Linux允许推迟的页分配,换句话说,只当你真的要用的时候才开始分配动作,比如写入数据时。所以,除非写入数据,否则你可以一直要更多内存。术语称之为乐观的内存分配。
查看/proc/
引用:$ cat /proc//status
VmPeak: 3141876 kB
VmSize: 3141876 kB
VmLck: 0 kB
VmHWM: 12556 kB
VmRSS: 12556 kB
VmData: 3140564 kB
VmStk: 88 kB
VmExe: 4 kB
VmLib: 1204 kB
VmPTE: 3072 kB
这是在B被杀之前的记录:
引用:$ cat /proc//status
VmPeak: 1072512 kB
VmSize: 1072512 kB
VmLck: 0 kB
VmHWM: 234636 kB
VmRSS: 204692 kB
VmData: 1071200 kB
VmStk: 88 kB
VmExe: 4 kB
VmLib: 1204 kB
VmPTE: 1064 kB
VmRSS需要再详细点解释。RSS是Resident Set Size,也就是当前进程在内存中分配的块。也注意,在B到OOM之前已经用掉了几乎全部交换分区,而A根本没用。很明显malloc()除了保留内存之外什么也没做。
另外一个问题是:既然没有写页,为什么有3056M这个上限?这暴露出另外一个限制。在32位系统上,内存地址有4GB。其中0-3GB是用户使用,3-4GB为内核空间。
注意:有内核补丁可以实现全部分配4GB给用户空间,需要一些上下文切换的开销。OOM的结论:
VM中没有可用页。
没有足够的用户地址空间。
以上两者。
另外,在linux 环境下,用malloc分配的内存空间会比可见的free memory要大(见下例,malloc size =0x7d000000 > MemFree: 1762136 kB),也是因为交换空间swap存在造成的。而嵌入式单板上没有swap区,就不会出现这个情况。
引用:[wind@fw-csvr mpc8313]$ cat /proc/meminfo
MemTotal: 2074844 kB
MemFree: 1762136 kB
Buffers: 21764 kB
Cached: 229040 kB
SwapCached: 23016 kB
Active: 236684 kB
Inactive: 38376 kB
[wind@fw-csvr mpc8313]$ ./mpc8313_mem_mini
Now doing DDR SDRAM test, please wait............
diagSDRAMSub[88] : malloc size =0x7d000000, addr = 0x3a5db008!
ddrMemDiag[53]: test size = 2000MB! time = 118s
swap交换区的知识参见:《揭开Linux系统Swap交换区之谜》