OOM与进程优先级
无    2019-02-13 18:36:53    1810    0    0
xianglijiaxing

 

 

 

Linux内核OOM机制

 

使用malloc分配内存,并不会立即触发OOM,存在一种机制overcommit特性

 

    By default, Linux follows an optimistic memory allocation strategy. This means that when malloc() returns non-NULL there is no guarantee that the memory really is available. This is a really bad bug. In case it turns out that the system is out of memory, one or more processes will be killed by the infamous OOM killer. In case Linux is employed under circumstances where it would be less desirable to suddenly lose some randomly picked processes, and moreover the kernel version is sufficiently recent, one can switch off this overcommitting behavior using a command like:

上面的描述中说明了在Linux中当malloc返回的是非空时,并不代表有可以使用的内存空间。Linux系统允许程序申请比系统可用内存更多的内存空间,这个特性叫做overcommit特性,这样做可能是为了系统的优化,因为不是所有的程序申请了内存就会立刻使用,当真正的使用时,系统可能已经回收了一下内存。但是,当你使用时Linux系统没有内存可以使用时,OOM Killer就会出来让一些进程退出。

 

Linux下有3种Overcommit的策略(参考内核文档:vm/overcommit-accounting),可以在/proc/sys/vm/overcommit_memory配置(取0,1和2三个值,默认是0)。 

(1)0:启发式策略,比较严重的Overcommit将不能得逞,比如你突然申请了128TB的内存。而轻微的overcommit将被允许。另外,root能Overcommit的值比普通用户要稍微多

(2)1: 永远允许overcommit,这种策略适合那些不能承受内存分配失败的应用,比如某些科学计算应用。 

(3)2: 永远禁止overcommit,在这个情况下,系统所能分配的内存不会超过swap+RAM*系数(/proc/sys/vm/overcmmit_ratio,默认50%,你可以调整),如果这么多资源已经用光,那么后面任何尝试申请内存的行为都会返回错误,这通常意味着此时没法运行任何新程序。

 

android中的值为1。

 

 

oom_adj

 

cat  /proc/sys/vm/overcommit_ratio

android中值为50

当然我可以修改proc/*pid*/oom_adj的值,这里的默认值为0,当我们设置为-17时,对于该进程来说,就不会触发OOM机制,被杀掉。

echo -17 > /proc/$(pidof sshd)/oom_adj

这里为什么是-17呢?这和Linux的实现有关系。在Linux内核中的oom.h文件中,可以看到下面的定义:

/* /proc//oom_adj set to -17 protects from the oom-killer */

#define OOM_DISABLE (-17)

/* inclusive */

#define OOM_ADJUST_MIN (-16)

#define OOM_ADJUST_MAX 15

 

这个oom_adj中的变量的范围为15到-16之间。越大越容易被kill。oom_score就是它计算出来的一个值,就是根据这个值来选择哪些进程被kill掉的。

总之,通过上面的分析可知,满足下面的条件后,就是启动OOM机制。

1) VM里面分配不出更多的page(注意linux kernel是延迟分配page策略,及用到的时候才alloc;所以malloc + memset才有效)。

2) 用户地址空间不足,这种情况在32bit机器上及user space超过了3GB,在64bit机器上不太可能发生。

 

一 : 前台进程 (Active Process): oom_adj为0。 前台进程包括 :

1 : 活动 正在前台接收用户输入

2:活动、服务与广播接收器正在执行一个onReceive事件的处理函数

3: 服务正在运行 onStart、onCreate或onDestroy事件处理函数。

二 : 已启动服务的进程(Started Service Process) :oom_adj值为0,这类进程包含一个已启动的服务。 服务并不直接与用户输入交互,因此服务的优先级 低于可见活动的优先级,但是,已启动服务的进程任被认为是前台进程,只有在活动以及可见活动需要资源时,已启动服务的进程才会被杀死。

三 :可见进程 (Visible Process): oom_adj 为 1。活动是可见的,但并不在前台,或者不响应用户的输入。例如,活动被非全屏或者透明的活动所遮挡。

四 :后台进程 (Backgroud Process): oom_adj 值为 2,这类进程不包含任何可见的活动与启动的服务。通常大量后台进程存在时,系统会采用(last-seen-first-kill)后见先杀的方式,释放资源为前台进程使用。

五 :主界面 (home process): oom_adj 为 4

六 :隐藏进程 (hidden process): oom_adj为 7

七 :内容提供者 (content provider):oom_adj 为 14

八 :空进程 (Empty process):oom_adj为 15

 

link:

Android 进程调度之ADJ算法

 http://gityuan.com/2016/08/07/android-adj/

 

oom_score

 

最终OOM killer是通过/proc//oom_score这个值来决定哪个进程被干掉的。这个值是系统综合进程的内存消耗量、CPU时间(utime + stime)、存活时间(uptime - start time)和oom_adj计算出的,消耗内存越多分越高,存活时间越长分越低。总之,总的策略是:损失最少的工作,释放最大的内存同时不伤及无辜的用了很大内存的进程,并且杀掉的进程数尽量少。 另外,Linux在计算进程的内存消耗的时候,会将子进程所耗内存的一半同时算到父进程中

 

(1)score初始值为该进程占用的total_vm;
(2)如果该进程有子进程,子进程独自占用的total_vm/2加到本进程score;
(3)score随着该进程的cpu_time以及run_time的增长而减少,也就是运行的时间越长,被kill掉的几率越小
(4) nice大于0的进程,score*2;
(5)对于拥有超级权限的进程,或者直接磁盘交互的进程降低score;
(6)如果和current进程在内存上没有交集,则该进程降低score;
(7)最后根据该进程的oom_adj,计算得出最终的score

 

oom_score_adj

 

 

 

 

多进程+ 前台service

 

多进程+ 普通Service

 

多进程之间使用AIDL + 路由功能  http://www.jianshu.com/p/1d7760eab1b8

 

http://blog.spinytech.com/

 

地图(百度地图本身是一个独立的进程)、加载图片模块化

 

灰色方法可以启动一个不显示通知的前台service(IntentService) + aidl 双进程守护

 

多进程 与 插件化的取舍

 

 

 

-----------------------------------------------------------------------------------------------------------------------------------

 

http://blog.csdn.net/u010307119/article/details/52495045

 

 https://www.cnblogs.com/andyzhuaz/p/8977506.html

 

 

 

 

上一篇: 笔记

下一篇: 目前已知的开源热修复方案

1810 人读过
立即登录, 发表评论.
没有帐号? 立即注册
0 条评论
文档导航