android的oomkiller_Android Low memory killer

Android Low memory

killer

by 永远的伊苏

Android中,进程的生命周期都是由系统控制的,即使用户关掉了程序,进程依然是存在于内存之中。这样设计的目的是为了下次能快速启动。当然,随着系统运行时间的增长,内存会越来越少。Android Kernel 会定时执行一次检查,杀死一些进程,释放掉内存。

那么,如何来判断,那些进程是需要杀死的呢?答案就是我们的标题:Low memory killer机制。

Android 的Low memory

killer是基于linux的OOM(out of memory) 规则改进而来的。 OOM通过一些比较复杂的评分机制,对进程进行打分,然后将分数高的进程判定为bad进程,杀死并释放内存。OOM只有当系统内存不足的时候才会启动检查,而Low memory killer 则是定时进行检查。

Low

memory killer 主要是通过进程的oom_adj

来判定进程的重要程度。oom_adj的大小和进程的类型以及进程被调度的次序有关。

Low

memory killer 的具体实现可参看:kernel/drivers/misc/lowmemorykiller.c

其原理很简单,在linux中,存在一个kswapd的内核线程,当linux回收存放分页的时候,kswapd线程将会遍历一张shrinker链表,并执行回调,定义如下:

所以只要注册

Shrinker,变可以在内存分页回收时根据规则释放内存,下面我们来看看其实现。

首先定义shrinker结构体,lowmem_shrink为回调函数的指针,当有内存分页回收的时候,这个函数将会被调用。

初始化模块时进行注册,结束时注销。

Android中,存在着一张内存阈值表,这张阈值表是可以在init.rc中进行配置的,

合理配置这张表,对于小内存设备有非常重要的作用。

我们来看lowmemorykiller.c中这张默认的阈值表:

Lowmeme_adj中各项数值代表阈值的警戒级数,lowmem_minfree代表对应级数的剩余内存。

也就是说,当系统的剩余内存为小于6MB时候,警戒级数为0,当系统内存剩余小于8M而大于

6M的时候,警戒级数为1,当内存小于64M大于16MB的时候,警戒级数为12.

Low memory killer

的规则就是根据当前系统的剩余内存多少来获取当前的警戒级数,如果进程的oom_adj大于警戒级数并且最大,进程将会被杀死(相同omm_adj的,则杀死占用内存较多的)。Omm_adj越小,代表进程越重要。一些前台的进程,oom_adj会比较小,而后台的服务,omm_adj会比较大,所以当内存不足的时候,Low memory killer 杀掉的必然先杀掉的是后台服务而不是前台的进程。

OK,现在我们来看具体代码,也就是lowmem_shrink这个回调函数:

首先通过global_page_state获取当前剩余内存大小,然后根据剩余内存和内存阈值表查找当前的内存警戒数min_adj。接着遍历所有进程,找到oom_adj大于min_adj并且oom_adj最大的进程:

进程的oom_adj

小于警戒阈值,则无视。

获取这个进程所占用的内存大小tasksize,如果小于比我们当前选出进程的内存,则无视。

如果大于则选中这个进程:

经过for_each的遍历,selected 就是我们选出要释放掉的bad进程,它具有下面两个条件:

Oom_adj大于当前警戒阈值并且最大。

在同样大小的oom_adj中,占用内存最多。

最后,我们释放掉这个进程的内存,通过force_sig(SIGKILL, selected)来向进程发送一个不可以忽略或阻塞的SIGKILL信号。

阈值表可以通过/sys/module/lowmemorykiller/parameters/adj和/sys/module/lowmemorykiller/parameters/minfree进行配置,例如在init.rc中:

# Write value must be consistent with the above properties.

write /sys/module/lowmemorykiller/parameters/adj 0,1,2,7,14,15

write /proc/sys/vm/overcommit_memory 1

write /sys/module/lowmemorykiller/parameters/minfree 1536,2048,4096,5120,5632,6144

class_start default

进程oom_adj同样可以进行设置,通过write

/proc//oom_adj,在init.rc中,init进程的pid为1,omm_adj被配置为-16,永远不会被杀死。

# Set init its forked children's oom_adj.

write /proc/1/oom_adj -16

Low memory killer的基本原理我们应该弄清了,正如我前面所说的,进程omm_adj的大小是跟进程的类型以及进程被调度的次序有关。进程的类型,可以在ActivityManagerService中清楚的看到:

static final int EMPTY_APP_ADJ;

static final int HIDDEN_APP_MAX_ADJ;

static final int HIDDEN_APP_MIN_ADJ;

static final int HOME_APP_ADJ;

static final int BACKUP_APP_ADJ;

static final int SECONDARY_SERVER_ADJ;

static final int HEAVY_WEIGHT_APP_ADJ;

static final int PERCEPTIBLE_APP_ADJ;

static final int VISIBLE_APP_ADJ;

static final int FOREGROUND_APP_ADJ;

static final int CORE_SERVER_ADJ = -12;

static final int SYSTEM_ADJ = -16;

ActivityManagerService定义各种进程的oom_adj,CORE_SERVER_ADJ代表一些核心的服务的omm_adj,数值为-12,由前面的分析可知道,这类进程永远也不会被杀死。

其他未赋值的都在static块中进行了初始化,是通过system/rootdir/init.rc进行配置的:

在init.rc中:

# Define the oom_adj values for the classes of

processes that can be

# killed by the kernel. These are used in

ActivityManagerService.

setprop ro.FOREGROUND_APP_ADJ 0

setprop ro.VISIBLE_APP_ADJ 1

setprop ro.SECONDARY_SERVER_ADJ 2

setprop ro.HIDDEN_APP_MIN_ADJ 7

setprop ro.CONTENT_PROVIDER_ADJ 14

setprop ro.EMPTY_APP_ADJ 15

# Define the memory thresholds at which the above

process classes will

# be killed. These numbers are in

pages (4k).

setprop ro.FOREGROUND_APP_MEM 1536

setprop ro.VISIBLE_APP_MEM 2048

setprop ro.SECONDARY_SERVER_MEM 4096

setprop ro.HIDDEN_APP_MEM 5120

setprop ro.CONTENT_PROVIDER_MEM 5632

setprop ro.EMPTY_APP_MEM 6144

由此我们知道EMPTY_APP 最容易被杀死,其实是CONTENT_PROVIDER ,FOREGROUND的进程很难被杀死。

现在我们再来说影响oom_adj的第二个因素,进程的调度次序。这涉及到了ActivityManagerService的复杂调度,我们下次再来看吧。呵呵。

See

you next time !!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/335812.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++ 11 深度学习(十二)函数新特性、内联函数、const详解

函数后置返回类型 //后置返回类型 auto fun(int, int)->int; 内联函数 在函数定义前增加关键字 inline ,使得该函数变成内联函数 (1) 适用于函数体很小,调用很频繁的函数类型,可以引入内联函数 (2) inline影响编译器,在编译阶段对inc…

apache pdfbox_Apache PDFBox 2

apache pdfboxApache PDFBox 2已于今年早些时候发布 , Apache PDFBox 2.0.1和Apache PDFBox 2.0.2已发布。 Apache PDFBox是开源的( Apache许可证版本2 )并且基于Java(因此易于使用,包括Java , Groovy &…

cad坐标归零lisp_CAD图怎么归零

展开全部原理,就是把图元Z轴线移动的负无穷远,然e68a84e8a2ad62616964757a686964616f31333335336530后移动到正无穷,除了块就可以Z轴线归零了。用autoLISP来解决。;;;;;;Z坐标归零;;(defun c:z0 ( / &kw &k1 #os1)(setvar "cmde…

dynamodb java_使用Java查询DynamoDB项

dynamodb java在上一篇文章中,我们继续在DynamoDB数据库上插入数据。 在本教程中,我们将对DynamoDB表发出一些基本查询。 主要规则是每个查询都必须使用哈希键。 查询的最简单形式是仅使用哈希键。 我们将在此表上查询Users表。 结果只有一个&#xff…

冰点还原离线激活_冰点还原密钥,小编告诉你如何激活冰点还原

冰点还原软件,它具有轻松安装、动态保护、实时瞬间恢复,操作简单的特点。安装了冰点还原的系统,无论进行了安装文件,还是删除文件、更改系统设置等操作,计算机重新启动后,一切将恢复成初始状态。不过这些都…

【WebRTC---源码篇】(四)WebRTC线程模型

常见的线程模型 1.为了解决频繁线程创建与销毁,在此模型中使用的线程池。在线程池创建的时候就将一些线程创建起来,以提高效率。通过控制线程数量来解决线程频繁切换。 2.一般线程与线程存在前后关系的,线程执行完毕之后生成一个新的任务(task1 , task2,task3---)插入到任…

java cuba_CUBA平台–用于快速应用程序开发的开源Java框架

java cuba传统上,自计算时代开始以来,企业软件开发自然面临着一个挑战,当时自然而然地,企业软件开发本应专注于解决实际的业务问题,但与此同时,开发人员必须在技术上花费大量时间和精力。解决方案的一面&am…

web project、web service project和java project的区别

java project就是普通的用java写的程序,直接就能运行的,web project,web service project不能直接运行,必须在容器里面运行,这个容器就是web server,例如tomcat,jboss。web project就是web工程,简单的讲做网…

WebRTC Qos优化杂记

WebRTC视频JitterBuffer详解 详细内容链接 JitterBuffer延迟换流畅 在丢包+延迟+抖动的弱网环境下,推流端通过NACK+FEC等方式做了一定的容错,但是可能并不能百分之百解决所有问题,而且通过SFU分发到拉流端之后,拉流端网络也可能有问题,这个时候需要JitterBuffer来做媒体…

keras添加正则化全连接_TensorFlow keras卷积神经网络 添加L2正则化

model keras.models.Sequential([#卷积层1keras.layers.Conv2D(32,kernel_size5,strides1,padding"same",data_format"channels_last",activationtf.nn.relu,kernel_regularizerkeras.regularizers.l2(0.01)),#池化层1keras.layers.MaxPool2D(pool_size2,…

java中什么时候应用异常_生产Java应用程序中的十大异常类型-基于1B事件

java中什么时候应用异常Pareto记录原理:97%的记录错误语句是由3%的唯一错误引起的 在最新的数据整理帖子之后,我们收到了很多反馈和问题,我们发现97%的记录错误是由10个唯一错误引起的 。 根据大众的需求&…

C++ 11 深度学习(十四)C++类

(一)综述:类是我们自己定义的数据类型 设计时要考虑的角度: 站在设计和实现的角度来考虑;站在使用者的角度考虑;父类,子类之间的考虑; (二)explicit 首先, C中的explicit关键字只…

手动编译 lombok_Lombok,一种编译时Java注释预处理器,可最大程度地减少代码大小...

手动编译 lombok在本文中,我们将看到如何在常规Java代码中使用lombok来最大程度地减少代码长度和冗余。 什么是Lombok? Lombok,一个编译时注释预处理器,有助于在编译时注入一些代码。 在详细介绍之前,我要求您应该从…

MyEclipse for Windows快捷键

文章目录编辑查询/替换导航调试重构其他自定义快捷键技巧编辑 快捷键功能说明Ctrl1快速修复(最经典的快捷键,就不用多说了,可以解决很多问题,比如import类、try catch包围等)CtrlShiftF格式化代码。团队有统一的代码格式&#xf…

微信小程序view动态长度_微信小程序实现动态获取元素宽高的方法分析

本文实例讲述了微信小程序实现动态获取元素宽高的方法。分享给大家供大家参考,具体如下:我以前一直以为微信小程序不能动态获取view元素的宽高。但是自从看到: wx.createSelectorQuery() 这个api接口,以前的某些问题就能得到解决了…

数据结构【双指针算法】

双指针一般应用于维护两个队列&#xff0c;或者同一队列。 常见写法如下 for (int i 0, j 0; i < n; i){while (j < i && check(i, j)) j;//每道题的具体逻辑} 双指针的核心思想是把如下O(n^2)的算法优化位O(n) for (int i 0; i < n; i){for (int j 0; …

antlr 语言 库_关于ANTLR的通用库的需求:使用反射来构建元模型

antlr 语言 库我是一名语言工程师&#xff1a;我使用多种工具来定义和处理语言。 在其他工具中&#xff0c;我使用ANTLR&#xff1a;它简单&#xff0c;灵活&#xff0c;可以围绕它进行构建。 但是我发现自己围绕ANTLR为不同的项目重建了类似的工具。 我看到两个问题&#xff…

Windows 如何通过命令启动和关闭 Tomcat

首先你的系统要安装tomcat&#xff0c;至于如何安装tomcat这里就不讲解了&#xff0c;接着你打开windows的DOS命令终端&#xff08;winR打开运行窗口&#xff0c;输入cmd即可&#xff09;&#xff0c;然后通过DOS命令切换到tomcat安装目录下的bin目录&#xff0c;最后执行start…

mysql超大表处理方式是_第29问:MySQL 的复制心跳说它不想跳了

问题最近年底&#xff0c;大家的数据库经常跑批量大事务&#xff0c;会发现复制突然断开&#xff0c;报错“心跳与本地信息不兼容”&#xff1a;会是什么原因&#xff1f;实验我们先来复现一下&#xff0c;再进行分析。宽油&#xff0c;做一对主从数据库&#xff1a;我们先造一…