uClinux下free memory太少导致死机解决方法: kswapd
引用:http://hi.baidu.com/kkernel/blog/item/16032e2af6226693033bf62a.html
错误信息>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Allocation of length 332616 from process 74 failed
Buffer memory: 196kB
Cache memory: 2540kB
Free pages: 676kB ( 0kB HighMem)
Zone:DMA freepages: 0kB min: 0kB low: 0kB high: 0kB
Zone:Normal freepages: 676kB min: 128kB low: 256kB high: 384kB
Zone:HighMem freepages: 0kB min: 0kB low: 0kB high: 0kB
( Active: 154, inactive: 530, free: 169 )
= 0kB)
49*4kB 6*8kB 7*16kB 2*32kB 2*64kB 1*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB = 676kB)
= 0kB)
Unable to allocate RAM for process text/data, errno 12
需要分配的空间是:332616 byte,low: 256kB high:384kB Free pages: 676kB
所以我们只要让low > 333 kB 可以取:384 kB
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
在linux的内存管理伙伴(buddy)算法中, kswapd内核线程会在free内存不够时被唤醒,来释放页高速缓存(cached).
在uClinux内存管理算法的默认设置中,当空闲内存少于700K左右后,kswapd会被唤醒。可是糟糕的是,在这种情况下(内存少于700K时),
如果运行需要分配大内存的程序时,会导致系统死机。
如下面邮件里提到的开启snmpd时的情况:snmpd那时候大概需要5MB的内存,可是free并没有那么多:
我们可以调节这个free内存的阀值,来始终保持有一定量的内存是空闲的。这里,我将这个阀值设为17.6MB(总共61MB内存情况下),如果空闲内存低于阀值时,kswapd就会被唤醒来释放内存。具体修改办法及分析如下:
修改内核源代码: uclinux-l200v40/linux-2.4.x/mmnommu/page_alloc.c中free_area_init_core()函数大约818行处:
将zone->pages_low = mask*2;改为zone->pages_low = mask*36;
将
zone->pages_high = mask*3;改为zone->pages_high = mask*54;
// page_high为page_low的3/2
在内存为61M时,当内存低于17620K时,kswapd线程就会被唤醒来释放cached部分内存:
uclinux-l200v40/linux-2.4.x/mmnommu/page_alloc.c中__alloc_pages()函数:
zone = zonelist->zones;
classzone = *zone;
if (classzone == NULL)
return NULL;
min = 1UL << order;
for (;;) {
zone_t *z = *(zone++);
if (!z)
break;
min += z->pages_low;
if (z->free_pages > min) {
page = rmqueue(z, order);
if (page)
return page;
}
}
classzone->need_balance = 1;
mb();
if (waitqueue_active(&kswapd_wait))
wake_up_interruptible(&kswapd_wait); //唤醒kswapd内核线程
在uclinux-l200v40/linux-2.4.x/mmnommu/vmscan.c中:
static int __init kswapd_init(void) //在内核启动时,启动kswapd线程
{
printk("Starting kswapd\n");
swap_setup();
kernel_thread(
kswapd, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
return 0;
}
kswapd定义如下:
int kswapd(void *unused)
{
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk);
daemonize();
strcpy(tsk->comm, "kswapd");
sigfillset(&tsk->blocked);
/*
* Tell the memory management that we're a "memory allocator",
* and that if we need more memory we should get access to it
* regardless (see "__alloc_pages()"). "kswapd" should
tsk->flags |= PF_MEMALLOC;
/*
* Kswapd main loop.
*/
for (;;) {
__set_current_state(TASK_INTERRUPTIBLE);
//可被中断,这是当然的了
add_wait_queue(&kswapd_wait, &wait);
//将自己加入到等待队列中,当free过低时会被唤醒
mb();
if (kswapd_can_sleep())
//如果可以继续睡觉的话,还是睡觉的好。
schedule();
//free不够了,当然不能再睡觉了,该干嘛还是得干嘛的,人不能总睡觉吧
__set_current_state(TASK_RUNNING);
remove_wait_queue(&kswapd_wait, &wait);
/*
* If we actually get into a low-memory situation,
* the processes needing more memory will wake us
* up on a more timely basis.
*/
kswapd_balance(); //这个函数就开始判断和释放cache了
run_task_queue(&tq_disk);
}
}
BTW: 查看运行程序占用多大内存的方法:
root:~> cat /proc/29/status
Name: snmpd
State: D (disk sleep)
Tgid: 29
Pid: 29
PPid: 1
TracerPid: 0
Uid: 0 0 0 0
Gid: 0 0 0 0
FDSize: 32
Groups: 0
Mem: 5102240 bytes
Slack: 2069141 bytes
Shared: 0 bytes
SigPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000001005
SigCgt: 0000000001004202
CapInh: 0000000000000000
CapPrm: 00000000fffffeff
CapEff: 00000000fffffeff
阅读(2416) | 评论(0) | 转发(0) |