Chinaunix首页 | 论坛 | 博客
  • 博客访问: 145185
  • 博文数量: 44
  • 博客积分: 2085
  • 博客等级: 大尉
  • 技术积分: 455
  • 用 户 组: 普通用户
  • 注册时间: 2009-07-31 11:03
文章分类

全部博文(44)

文章存档

2013年(3)

2011年(8)

2010年(11)

2009年(22)

我的朋友

分类: LINUX

2009-09-11 10:22:33

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
阅读(2376) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~