注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

民主与科学

独立之人格,自由之思想

 
 
 

日志

 
 

Android Low memory killer(下)  

2011-05-24 21:17:19|  分类: Android内存 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
本文参照: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_state获取当前剩余内存大小;接着检测lowmem_adjlowmem_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 };
到此结束!
  评论这张
 
阅读(2445)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017