Android Low memory killer(下)

本文参照:http://blog.sina.com.cn/s/blog_4d66a3cb0100prfe.html
在阅读本文前,请先阅读《 Android Low memory killer(上)
在了解了Low Memory Killer的原理之后,我来看其具体实现,lowmemorykiller.clowmem_shrink函数。
static int lowmem_shrink(int nr_to_scan, gfp_t gfp_mask)
{
    struct task_struct 
*p;
    struct task_struct 
*selected = NULL;
    
int rem = 0;
    int tasksize;
    
int i;
    
int min_adj = OOM_ADJUST_MAX + 1;
    
int selected_tasksize = 0;
    
int array_size = ARRAY_SIZE(lowmem_adj);
    
int other_free = global_page_state(NR_FREE_PAGES);
    
int other_file = global_page_state(NR_FILE_PAGES);
    
if(lowmem_adj_size < array_size)
        array_size 
= lowmem_adj_size;
    
if(lowmem_minfree_size < array_size)
        array_size 
= lowmem_minfree_size;
    
for(i = 0; i < array_size; i++) {
        
if (other_free < lowmem_minfree[i] &&
            other_file 
< lowmem_minfree[i]) {
            min_adj 
= lowmem_adj[i];
            break;
        }
    }
    
if(nr_to_scan > 0)
        lowmem_print(
3"lowmem_shrink %d, %x, ofree %d %d, ma %d\n", nr_to_scan, 
                 gfp_mask, other_free, other_file, min_adj);
    
rem = global_page_state(NR_ACTIVE_ANON) +
        global_page_state(NR_ACTIVE_FILE) +
        global_page_state(NR_INACTIVE_ANON) 
+
        global_page_state(NR_INACTIVE_FILE);
    
if (nr_to_scan <= 0 || min_adj == OOM_ADJUST_MAX + 1) {
        lowmem_print(
5"lowmem_shrink %d, %x, return %d\n", nr_to_scan, gfp_mask, 
                 
rem);
        return rem;
    }

    read_lock(
&tasklist_lock);
    for_each_process(p) {
        
if (p->oomkilladj < min_adj || !p->mm)
            continue;
        tasksize 
= get_mm_rss(p->mm);
        
if (tasksize <= 0)
            continue;
        
if (selected) {
            
if (p->oomkilladj < selected->oomkilladj)
                continue;
            
if (p->oomkilladj == selected->oomkilladj &&
                tasksize 
<= selected_tasksize)
                continue;
        }
        selected 
= p;
        selected_tasksize 
= tasksize;
        lowmem_print(
2"select %d (%s), adj %d, size %d, to kill\n",
                     p
->pid, p->comm, p->oomkilladj, tasksize);
    }
    
if(selected != NULL) {
        lowmem_print(
1"send sigkill to %d (%s), adj %d, size %d\n",
                     selected
->pid, selected->comm,
                     selected
->oomkilladj, selected_tasksize);
        force_sig(SIGKILL, selected);
        
rem -= selected_tasksize;
    }
    lowmem_print(
4"lowmem_shrink %d, %x, return %d\n", nr_to_scan, gfp_mask, rem);
    read_unlock(&tasklist_lock);
    return 
rem;
}
首先通过 global_page_stat e获取当前剩余内存大小;接着检测 lowmem_adj lowmem_minfree 数组的大小(元素个数)是否一致,如果不一致则以最小数组的大小为基准;然后根据剩余内存和内存阈值数组 lowmem_minfree 查找当前的内存警戒数 min_adj 。接着遍历所有进程,找到oom_adj大于min_adj并且oom_adj最大的进程。
进程的 oom_adj 小于警戒阈值,则无视。 进程的 oom_adj 大于等于于警戒阈值,则 获取这个进程所占用的内存大小 tasksize ,如果小于比我们当前选出进程的内存,则无视。如果大于则选中这个进程。
经过 for_each 的遍历, selected  就是我们选出要释放掉的bad进程,它具有下面两个条件:
第一、Oom_adj大于当前警戒阈值并且最大。
第二、在同样大小的oom_adj中,占用内存最多。
最后,我们释放掉这个进程的内存,通过 force_sig(SIGKILL, selected) 来向进程发送一个不可以忽略或阻塞的SIGKILL信号。
在lowmem_shrink函数中多处用到了 global_page_state 函数。
它被定义在了 common/include/linux/vmstat.h 中,
static inline unsigned long   global_page_state (enum zone_stat_item item)
{
long x = atomic_long_read(&vm_stat[item]);
#ifdef CONFIG_SMP
if (x < 0)
x = 0;
#endif
return x;
}
global_page_state函数的参数 NR_FREE_PAGES 等使用 zone_stat_item 枚举,被定义在 common/include/linux/mmzone.h 中,具体代码如下:
enum zone_stat_item {
    NR_FREE_PAGES,
    NR_LRU_BASE,
    NR_INACTIVE_ANON 
= NR_LRU_BASE,
    NR_ACTIVE_ANON,
    NR_INACTIVE_FILE,
    NR_ACTIVE_FILE,
#ifdef CONFIG_UNEVICTABLE_LRU
    NR_UNEVICTABLE,
    NR_MLOCK,
#
else
    NR_UNEVICTABLE 
= NR_ACTIVE_FILE, /* 避免编译错误*/
    NR_MLOCK 
= NR_ACTIVE_FILE,
#endif
    NR_ANON_PAGES,        
/* 匿名映射页面*/
    NR_FILE_MAPPED,        
/*映射页面*/
    NR_FILE_PAGES,
    NR_FILE_DIRTY,
    NR_WRITEBACK,
    NR_SLAB_RECLAIMABLE,
    NR_SLAB_UNRECLAIMABLE,
    NR_PAGETABLE,
    NR_UNSTABLE_NFS,
    NR_BOUNCE,
    NR_VMSCAN_WRITE,
    NR_WRITEBACK_TEMP,    
/* 使用临时缓冲区*/
#ifdef CONFIG_NUMA
    NUMA_HIT,            
/* 在预定节点上分配*/
    NUMA_MISS,            
/* 在非预定节点上分配*/
    NUMA_FOREIGN,
    NUMA_INTERLEAVE_HIT,
    NUMA_LOCAL,            
/* 从本地页面分配*/
    NUMA_OTHER,            
/* 从其他节点分配 */
#endif
    NR_VM_ZONE_STAT_ITEMS };
到此结束!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值