android 应用程序 lowlow memory killerkiller 怎么解决

The timing to start Android Low Memory killer - Stack Overflow
to customize your list.
Join the Stack Overflow Community
Stack Overflow is a community of 4.7 million programmers, just like you, helping each other.
J it only takes a minute:
As we know, low memory killer starts at a fixed time. How long is the "fixed time"? Where is the code to configure this?
Android LMK doesn't start freeing memory at some particular time, but it depends on minfree values:
/sys/module/lowmemorykiller/parameters/minfree
For example, if cat
/sys/module/lowmemorykiller/parameters/minfree has the following values:
Then that means these values are thresholds memory for starting killing of these particular kind of processes.
FOREGROUND_APP:1536
VISIBLE_APP:2048
SECONDARY_SERVER:4096
HIDDEN_APP:5120
CONTENT_PROVIDER:5632
EMPTY_APP:6144
E.g., when free memory (RAM) in system is less than (4)= 24 MB, then LMK will start killing EMPTY_APP processes. Similarly if still memory condition don't improve it will start killing process in EMPTY_APP-&CONTENT_PROVIDER-&....-&FOREGROUND_APP (last to be killed, this should never happen).
14.8k52143
In the asynchronous case, LMK is timed by the kernel pageout daemon (kswapd). So I suppose you can dig a little deeper into kswapd control flow to figure out if it's wake up time is bounded which will provide a part answer to your question on timing constraints.
The LMK shrinker callback can also be invoked outside of the kswapd context. This occurs when the system performs a direct synchronous page reclaim (see. mm/page_alloc.c)
Reference notes:
Related SO Questions/Answers
Your Answer
Sign up or
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Post as a guest
By posting your answer, you agree to the
Not the answer you're looking for?
Browse other questions tagged
Stack Overflow works best with JavaScript enabledAndroid分析之LowMemoryKiller_Linux编程_Linux公社-Linux系统门户网站
你好,游客
Android分析之LowMemoryKiller
来源:Linux社区&
作者:Linux
Linux操作系统的传统理念就是内存用的越多越好,尽可能拿来用,既然被尽量的使用,自然应该有清除机制。以Linux为基础,自然部分继承了这个特性。Android使用lowmemorykiller在达到某个内存门限的情况下去选择进程删除来释放内存。关键的配置文件有如下两个,/sys/module/lowmemorykiller/parameters/adj和/sys/module/lowmemorykiller/parameters/minfree配置系统的相关参数。
adj文件包含队列包含oomadj队列,当对应的minfree值达到,则进程的oomadj如果大于这个值将被杀掉。
minfree包含对应oom_adj的警戒值。
参考如下:oom_adj&&&& 内存警戒值( 以4K为单位)0&&&&&&&&&&&& 15361&&&&&&&&&&&& 20482&&&&&&&&&&&& 40967&&&&&&&&&&&& 512014&&&&&&&&&&&& 563215&&&&&&&&&&&& 6144一般情况下,默认设置在system/core/rootdir/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.BACKUP_APP_ADJ 2&&& setprop ro.HOME_APP_ADJ 4&&& 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.BACKUP_APP_MEM 4096&&& setprop ro.HOME_APP_MEM 4096&&& setprop ro.HIDDEN_APP_MEM 5120&&& setprop ro.CONTENT_PROVIDER_MEM 5632&&& setprop ro.EMPTY_APP_MEM 6144
# Write value must be consistent with the above properties.# Note that the driver only supports 6 slots, so we have HOME_APP at the# same memory level as services.&&& write /sys/module/lowmemorykiller/parameters/adj 0,1,2,7,14,15
&&& write /sys/module/lowmemorykiller/parameters/minfree 96,44
&&& # Set init its forked children's oom_adj.&&& write /proc/1/oom_adj -16
实际上在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java中定义了两个更高的优先级。// This is a process running a core server, such as telephony. Definitely// don't want to kill it, but doing so is not completely fatal.static final int CORE_SERVER_ADJ = -12;
// The system process runs at the default adjustment.static final int SYSTEM_ADJ = -16;
根据以上分析,对于某些小内存设备,我们可以调整对应的门限值,例如:一般调整后三个值。echo "96,,20480"&/sys/module/lowmemorykiller/parameters/minfree
相关资讯 & & &
& (07/13/:14)
& (08/11/:27)
& (05/06/:13)
& (04/17/:32)
& (05/31/:15)
& (04/02/:07)
   同意评论声明
   发表
尊重网上道德,遵守中华人民共和国的各项有关法律法规
承担一切因您的行为而直接或间接导致的民事或刑事法律责任
本站管理人员有权保留或删除其管辖留言中的任意内容
本站有权在网站内转载或引用您的评论
参与本评论即表明您已经阅读并接受上述条款扫描下载MIUI论坛APP
经验1994 米
在线时间306 小时
版本5.7.15
机型小米手机3/4 WCDMA版
签到次数41
MIUI版本5.7.15
本帖最后由 anderson 于
13:34 编辑
准备写这个专题之前,心里是有点忐忑的。首先Android内存管理机制相当复杂,想要讲清楚比较困难;其次对于绝大多数用户来说,只关心内存够不够用,至于内存如何管理的这种技术细节,不是用户需要去考虑的,写这样一个专题有没有意义?毕竟我们是用手机,不是来研究手机的。最后的顾虑是这个专题会不会太技术化了,绝大部分用户不会看或者说缺乏相应的背景。但是有一种激励促使着我去写这样一个专题,一直以来,MIUI团队在与用户互动的过程中也同时在向用户学习,你们的一些建议或者点子总会给我们启示,这个专题中我相信你们同样能给以启示。虽然说内存管理是一个很技术的话题,但我们仍可以从用户的角度去看这些问题,内存管理是如何影响我们使用手机,作为用户,我们能做些什么。我会尽力使这样一个专题不那么技术化,但是仍旧免不了会有一些技术术语以及实现相关的讨论,如果有兴趣,我们就一起看看吧。
我们首先从用户发的一个帖子开始:“”,在这个帖子中提到了&alter minfree&选项,在这一篇中我们就讲讲这个是什么,它是如何工作的。
(1)Android是一个多任务系统,也就是说可以同时运行多个程序,这个大家应该很熟悉。一般来说,启动运行一个程序是有一定的时间开销的,因此为了加快运行速度,当你退出一个程序时,Android并不会立即杀掉它,这样下次再运行该程序时,可以很快的启动。随着系统中保留的程序越来越多,内存肯定会出现不足,这个时候Android系统开始挥舞屠刀杀程序。这里就有一个很明显的问题,杀谁?
(2)Android系统中杀程序的这个刽子手被称作&LowMemory Killer&,它是在Linux内核中实现的。这里它实现了一个机制,由程序的重要性来决定杀谁。通俗来说,谁不干活,先杀谁。Android将程序的重要性分成以下几类,按照重要性依次降低的顺序:
名称 oom_adj 解释 FOREGROUD_APP 0 前台程序,可以理解为你正在使用的程序 VISIBLE_APP 1 用户可见的程序 SECONDARY_SERVER 2 后台服务,比如说QQ会在后台运行服务 HOME_APP 4 HOME,就是主界面 HIDDEN_APP 7 被隐藏的程序 CONTENT_PROVIDER 14 内容提供者,EMPTY_APP
空程序,既不提供服务,也不提供内容
其中每个程序都会有一个oom_adj值,这个值越小,程序越重要,被杀的可能性越低。
(3)除了上述程序重要性分类之外,Android系统还维护着另外一张表,这张表是一个对应关系,以N1为例:
oom_adj 内存警戒值( 以4K为单位)
0 1536 1 2048 2 4096 7 5120 14 5632 15 6144这个表是定义了一个对应关系,每一个警戒值对应了一个重要性值,当系统的可用内存低于某个警戒值时,就杀掉所有大于该警戒值对应的重要性值的程序。比如说,当可用内存小于6144 * 4K = 24MB时,开始杀所有的EMPTY_APP,当可用内存小于5632 * 4K = 22MB时,开始杀所有
的CONTENT_PROVIDER和EMPTY_APP。
(4) alter minfree改的是什么呢,上面这张对应表是由两个文件组成的:
/sys/module/lowmemorykiller/parameters/adj和/sys/module/lowmemorykiller/parameters/minfree。
alter minfreee就是修改/sys/module/lowmemorykiller/parameters/minfree这个文件的,举例来说,如果把最后一项改为32 * 1024,那么当可用内存小于128MB是,就开始杀所有的EMPTY_APP。
这个专题的第一贴就到此结束,我们大致的讲了一下在内核里是如何处理low memory的,当然,实际上内核中的内存管理非常复杂,也不可能在这样的一个帖子中去展开,下一篇我们跳出内核层,去应用层看看。
分享到微信朋友圈
打开微信,点击底部的“发现”,使用 “扫一扫” 即可将网页分享到我的朋友圈。
已有&6&人评分
MIUI 因你更精彩!
感谢分享^_^
精品文章^_^
MIUI 因你更精彩!
精品文章^_^
经验2857 米
在线时间643 小时
版本3.8.16
积分 3441, 距离下一级还需 1559 积分
积分 3441, 距离下一级还需 1559 积分
机型Google Nexus 5
签到次数125
MIUI版本3.8.16
顶技术贴,先沙发个再看
经验3886 米
在线时间408 小时
版本6.9.22
MIUI V10 秘密测试组
积分 4788, 距离下一级还需 212 积分
积分 4788, 距离下一级还需 212 积分
机型小米手机5
签到次数149
MIUI版本6.9.22
技术贴太深奥了。。。
都说难看所以——御用主题,不分不享,坚决不融合。
经验545 米
在线时间1442 小时
头像被屏蔽
机型MOTO Milestone
一不小心坐地板上
签名被屏蔽
经验545 米
在线时间1442 小时
头像被屏蔽
机型MOTO Milestone
大师能不能换个图案啊,老看这个容易审美疲劳
签名被屏蔽
经验12220 米
威望468 米
在线时间3231 小时
机型小米手机5
签到次数158
MIUI版本6.9.6
技术贴~~~~
我的微博:
经验158 米
在线时间58 小时
版本JLB12.0
积分 205, 距离下一级还需 295 积分
积分 205, 距离下一级还需 295 积分
机型小米手机2/2S
MIUI版本JLB12.0
太有意思了,技术,技术纯粹的技术。
经验990 米
在线时间312 小时
版本2.12.21
积分 1309, 距离下一级还需 691 积分
积分 1309, 距离下一级还需 691 积分
机型HTC One X
签到次数10
MIUI版本2.12.21
期待楼主下篇文章
经验20579 米
在线时间2228 小时
机型小米手机5
签到次数269
MIUI版本6.9.7
占楼沙发呵呵:loveliness:
欢迎各位朋友到MIUI大家庭
经验3886 米
在线时间408 小时
版本6.9.22
MIUI V10 秘密测试组
积分 4788, 距离下一级还需 212 积分
积分 4788, 距离下一级还需 212 积分
机型小米手机5
签到次数149
MIUI版本6.9.22
刚换过绿色的那个~~!姜饼主题。。。:lol
都说难看所以——御用主题,不分不享,坚决不融合。
1000万用户纪念勋章
MIUI1000万用户纪念勋章
MIUI 100周
100周发布纪念勋章
小米手机元器件合体活动勋章
小米求合体勋章
关注新浪微博
已关注新浪微博
MIUI五周年
MIUI五周年纪念勋章
小米手机1终身荣誉勋章
小米手机1终身荣誉勋章
已关注微信
已关注极客秀微信
关注腾讯微博
已关注腾讯微博
一周年纪念勋章
一周年纪念勋章
MIUI 3000万
MIUI 3000万发烧友纪念勋章
Copyright (C) 2016 MIUI
京ICP备号 | 京公网安备34号 | 京ICP证110507号2222人阅读
【Android —
机制】(23)
前段时间碰到一个apk多个process依次开跑,跑到最后一个process的时候,第一个process给kill掉了,虽然第一个process中含有broadcast receive,被kill掉的原因是由于触发到了lowmemorykiller,这样一来apk最后的结果就异常了~ 尝试再三 规避掉了这个问题,记录一下~
撰写不易,转载需注明出处:本文来自 的博客!
andorid用户层的application process ,在各种activity生命周期切换时,会触发AMS中的回收机制,比如启动新的apk,一直back 退出一个apk,在5.1上的代码来看,除了android AMS中默认的回收机制外,还会去维护一个oom adj 变量,作为linux层 lowmemorykiller的参考依据。
AMS回收机制
入口为trimApplications()
可以发现很多地方有调用,stop
unregisterreceiver之类的操作时都会去触发回收:
final void trimApplications() {
synchronized (this) {
for (i=mRemovedProcesses.size()-1; i&=0; i--) {
final ProcessRecord app = mRemovedProcesses.get(i);
if (app.activities.size() == 0
&& app.curReceiver == null && app.services.size() == 0) {
TAG, "Exiting empty application process "
+ app.processName + " ("
+ (app.thread != null ? app.thread.asBinder() : null)
if (app.pid & 0 && app.pid != MY_PID) {
app.kill("empty", false);
app.thread.scheduleExit();
} catch (Exception e) {
cleanUpApplicationRecordLocked(app, false, true, -1);
mRemovedProcesses.remove(i);
if (app.persistent) {
, false, null );
updateOomAdjLocked();
mRemovedProcesses 列表中主要包含了 crash 的进程、5 秒内没有响应并被用户选在强制关闭的进程、以及应用开发这调用 killBackgroundProcess 想要杀死的进程。调用 Process.killProcess 将所有此类进程全部杀死。
updateOomAdjLocked
计算更新所有process的 oomadj
final void updateOomAdjLocked() {
// First update the OOM adjustment for each of the
// application processes based on their current state.
int curCachedAdj = ProcessList.CACHED_APP_MIN_ADJ;
int nextCachedAdj = curCachedAdj+1;
int curEmptyAdj = ProcessList.CACHED_APP_MIN_ADJ;
int nextEmptyAdj = curEmptyAdj+2;
for (int i=N-1; i&=0; i--) {
ProcessRecord app = mLruProcesses.get(i);
if (!app.killedByAm && app.thread != null) {
app.procStateChanged =
computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now);
applyOomAdjLocked(app, TOP_APP, true, now);
computeOomAdjLocked 计算当前process的adj,详细规则就不贴了,大体会根据 top activity .receiver.service process state 一大堆相关的因素去得出一个adj值。
adj 值 (-17 ~15)
越小优先级越高,从注释能看出来,策略在kernel中的lowmemorykiller驱动中实现
这里看下定义 在\frameworks\base\services\core\java\com\android\server\am\ProcessList.java :
// This is a process only hosting activities that are not visible,
// so it can be killed without any disruption.
static final int CACHED_APP_MAX_ADJ = 15;
static final int CACHED_APP_MIN_ADJ = 9;
// The B list of SERVICE_ADJ
// services that aren't as shiny and interesting as the ones in the A list.
static final int SERVICE_B_ADJ = 8;
// This is the process of the previous application that the user was in.
// This process is kept above other things, because it is very common to
// switch back to the previous app.
This is important both for recent
// task switch (toggling between the two top recent apps) as well as normal
// UI flow such as clicking on a URI in the e-mail app to view in the browser,
// and then pressing back to return to e-mail.
static final int PREVIOUS_APP_ADJ = 7;
// This is a process holding the home application
// avoiding killing it, even if it would normally be in the background,
// because the user interacts with it so much.
static final int HOME_APP_ADJ = 6;
// This is a process holding an application service
// have much of an impact as far as the user is concerned.
static final int SERVICE_ADJ = 5;
// This is a process with a heavy-weight application.
It is in the
// background, but we want to try to avoid killing it.
Value set in
// system/rootdir/init.rc on startup.
static final int HEAVY_WEIGHT_APP_ADJ = 4;
// This is a process currently hosting a backup operation.
Killing it
// is not entirely fatal but is generally a bad idea.
static final int BACKUP_APP_ADJ = 3;
// This is a process only hosting components that are perceptible to the
// user, and we really want to avoid killing them, but they are not
// immediately visible. An example is background music playback.
static final int PERCEPTIBLE_APP_ADJ = 2;
// This is a process only hosting activities that are visible to the
// user, so we'd prefer they don't disappear.
static final int VISIBLE_APP_ADJ = 1;
// This is the process running the current foreground app.
We'd really
// rather not kill it!
static final int FOREGROUND_APP_ADJ = 0;
// This is a process that the system or a persistent process has bound to,
// and indicated it is important.
static final int PERSISTENT_SERVICE_ADJ = -11;
// This is a system persistent process, such as telephony.
Definitely
// don't want to kill it, but doing so is not completely fatal.
static final int PERSISTENT_PROC_ADJ = -12;
// The system process runs at the default adjustment.
static final int SYSTEM_ADJ = -16;
// Special code for native processes that are not being managed by the system (so
// don't have an oom adj assigned by the system).
static final int NATIVE_ADJ = -17;
applyOomAdjLocked
将上面计算好的adj值经过一定的修整,设置到对应的process。
只关注跟lowmemorykiller 相关的调用接口, 省略了AMS中自己根据PROCESS_STATE的 kill策略, 大体有如下:
必须是非 persistent 进程,即非系统进程;
必须是空进程,即进程中没有任何 activity 存在。如果杀死存在 Activity 的进程,有可能关闭用户正在使用的程序,或者使应用程序恢复的时延变大,从而影响用户体验;
必须无 broadcast receiver。运行 broadcast receiver 一般都在等待一个事件的发生,用户并不希望此类程序被系统强制关闭;
进程中 service 的数量必须为 0。存在 service 的进程很有可能在为一个或者多个程序提供某种服务,如 GPS 定位服务。杀死此类进程将使其他进程无法正常服务。
看下 applyOomAdjLocked中的核心:
private final boolean applyOomAdjLocked(ProcessRecord app,
ProcessRecord TOP_APP, boolean doingAll, long now) {
if (app.curAdj != app.setAdj) {
ProcessList.setOomAdj(app.pid, .uid, app.curAdj);
if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
TAG, "Set " + app.pid + " " + app.processName +
" adj " + app.curAdj + ": " + app.adjType);
app.setAdj = app.curA
设置oomadj ,继续看 ProcessList.java
* Set the out-of-memory badness adjustment for a process.
* pid The process identifier to set.
* uid The uid of the app
* amt Adjustment value -- lmkd allows -16 to +15.
public static final void setOomAdj(int pid, int uid, int amt) {
if (amt == UNKNOWN_ADJ)
long start = SystemClock.elapsedRealtime();
ByteBuffer buf = ByteBuffer.allocate(4 * 4);
buf.putInt(LMK_PROCPRIO);
buf.putInt(pid);
buf.putInt(uid);
buf.putInt(amt);
writeLmkd(buf);
long now = SystemClock.elapsedRealtime();
if ((now-start) & 250) {
Slog.w("ActivityManager", "SLOW OOM ADJ: " + (now-start) + "ms for pid " + pid
+ " = " + amt);
writeLmkd 写process pid uid 以及adj 的buf, 以一个定义command打头
private static void writeLmkd(ByteBuffer buf) {
for (int i = 0; i & 3; i++) {
if (sLmkdSocket == null) {
if (openLmkdSocket() == false) {
Thread.sleep(1000);
} catch (InterruptedException ie) {
sLmkdOutputStream.write(buf.array(), 0, buf.position());
} catch (IOException ex) {
Slog.w(ActivityManagerService.TAG,
"Error writing to lowmemorykiller socket");
sLmkdSocket.close();
} catch (IOException ex2) {
sLmkdSocket = null;
可以看到try了3次 ,去打开对应的socket 然后写数据,openLmkdSocket 实现如下,android的 LocalSocket 机制,通过lmkd 这个socket通信
sLmkdSocket = new LocalSocket(LocalSocket.SOCKET_SEQPACKET)
sLmkdSocket.connect(
new LocalSocketAddress("lmkd",
LocalSocketAddress.Namespace.RESERVED))
sLmkdOutputStream = sLmkdSocket.getOutputStream()
这是作为client去请求connect ,而service端的处理在 \system\core\lmkd\lmkd.c
, 可以看下这个service的启动:
service lmkd /system/bin/lmkd
class core
socket lmkd seqpacket 0660 system system
标准的 C/S模式,AMS中发起的通信command 开头种类,以及buf格式 如下:
static final byte LMK_TARGET = 0;
static final byte LMK_PROCPRIO = 1;
static final byte LMK_PROCREMOVE = 2;
设置单一process 用的是 LMK_PROCPRIO
设置整个LMK adj minfree策略的是 LMK_TARGET
LMK_PROCREMOVE kill process用
lmkd service
这个service 的代码比较短 1K不到,机制也比较简单:
int main(int argc __unused, char **argv __unused) {
struct sched_param param = {
.sched_priority = 1,
mlockall(MCL_FUTURE);
sched_setscheduler(0, SCHED_FIFO, &param);
if (!init())
mainloop();
ALOGI("exiting");
init 那些socket相关,注册event handle func ,最后跳到mainloop去 循环poll等待
ctrl_lfd = android_get_control_socket("lmkd");
if (ctrl_lfd & 0) {
ALOGE("get lmkd control socket failed");
return -1;
细节不做关注,直接看收到刚刚 AMS那边发过来的command buf 的处理:
static void ctrl_command_handler(void) {
int ibuf[CTRL_PACKET_MAX / sizeof(int)];
int cmd = -1;
len = ctrl_data_read((char *)ibuf, CTRL_PACKET_MAX);
if (len &= 0)
nargs = len / sizeof(int) - 1;
if (nargs & 0)
cmd = ntohl(ibuf[0]);
switch(cmd) {
case LMK_TARGET:
targets = nargs / 2;
if (nargs & 0x1 || targets & (int)ARRAY_SIZE(lowmem_adj))
cmd_target(targets, &ibuf[1]);
case LMK_PROCPRIO:
if (nargs != 3)
cmd_procprio(ntohl(ibuf[1]), ntohl(ibuf[2]), ntohl(ibuf[3]));
case LMK_PROCREMOVE:
if (nargs != 1)
cmd_procremove(ntohl(ibuf[1]));
ALOGE("Received unknown command code %d", cmd);
ALOGE("Wrong control socket read length cmd=%d len=%d", cmd, len);
先看上面对应的LMK_PROCPRIO
设置某个process 的adj ,核心如下:
snprintf(path, sizeof(path), "/proc/%d/oom_score_adj", pid);
snprintf(val, sizeof(val), "%d", lowmem_oom_adj_to_oom_score_adj(oomadj));
writefilestring(path, val);
直接写process对应的文件节点,传下来的adj值 做了一个转换再写进 oom_score_adj:
static int lowmem_oom_adj_to_oom_score_adj(int oom_adj)
if (oom_adj == OOM_ADJUST_MAX)
return OOM_SCORE_ADJ_MAX;
return (oom_adj * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE;
kernel驱动中process manager 会有对应的处理机制 ,转换后个oom_score_adj保存在进程结构体
kernel\include\linux\sched.h
task_struct-&signal_struct-&short oom_score_
/* OOM kill score adjustment */
lowmemorykiller driver
kernel中的支持:
autoconf.h中
#define CONFIG_ANDROID_LOW_MEMORY_KILLER 1
可自行到kernel中 make menuconfig 查看
驱动目录:\kernel\drivers\staging\android\lowmemorykiller.c
static int __init lowmem_init(void)
register_shrinker(&lowmem_shrinker);
#ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES
__module_param_call(MODULE_PARAM_PREFIX, adj,
&lowmem_adj_array_ops,
.arr = &__param_arr_adj,
S_IRUGO | S_IWUSR, -1);
__MODULE_PARM_TYPE(adj, "array of short");
module_param_array_named(adj, lowmem_adj, short, &lowmem_adj_size,
S_IRUGO | S_IWUSR);
module_param_array_named(minfree, lowmem_minfree, uint, &lowmem_minfree_size,
S_IRUGO | S_IWUSR);
注册了一个shrinker ,这个机制之前没接触过,大体的意义就是向系统注册了这个shrinker 回调函数之后,当系统空闲内存页面不足时会调用。
CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES
支持动态改 策略阀门 值。
另外注册了文件ops 以及节点 adj .minfree 分别与lowmem_adj
. lowmen_minfree
数组成对应关系
策略数组以及阀值,两个数组之间也是一一对应关系,当内存小于64M时 就去准备 kill adj &=12 的process,取最低优先级 先kill, 比如此时有3个进程分别为 12
14 ,那么首先kill掉的是 14 ,kill之后还是少于64M 那么两个12 adj之间,先杀占用高的,这个函数实现在下面的 lowmem_shrink 中。
static short lowmem_adj[6] = {
static int lowmem_adj_size = 4;
static int lowmem_minfree[6] = {
16 * 1024,
先看下处理函数 lowmem_shrinker:
static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
struct task_struct *
struct task_struct *selected = NULL;
int rem = 0;
short min_score_adj = OOM_SCORE_ADJ_MAX + 1;
int minfree = 0;
int selected_tasksize = 0;
short selected_oom_score_
int array_size = ARRAY_SIZE(lowmem_adj);
int other_free = global_page_state(NR_FREE_PAGES) - totalreserve_
int other_file = global_page_state(NR_FILE_PAGES) -
global_page_state(NR_SHMEM);
if (lowmem_adj_size & array_size)
array_size = lowmem_adj_
if (lowmem_minfree_size & array_size)
array_size = lowmem_minfree_
for (i = 0; i & array_ i++) {
//依次遍历策略阀值数组,从小到大,根据当前memory free情况,取触发adj值
minfree = lowmem_minfree[i];
if (other_free & minfree && other_file & minfree) {
min_score_adj = lowmem_adj[i];
//这里得到的min_score_adj
就是此时内存状态下 将会kill掉的最小score_adj
for_each_process(tsk) {
tasksize = get_mm_rss(p-&mm);
if (selected) {
if (oom_score_adj & selected_oom_score_adj)
if (oom_score_adj == selected_oom_score_adj &&
tasksize &= selected_tasksize)
}//可以看到 遍历一圈process 只为找到一个 oom_score_adj tasksize 最大的process
selected =
selected_tasksize =
selected_oom_score_adj = oom_score_
if (selected) {
lowmem_print(1, "Killing '%s' (%d), adj %hd,\n" \
to free %ldkB on behalf of '%s' (%d) because\n" \
cache %ldkB is below limit %ldkB for oom_score_adj %hd\n" \
Free memory is %ldkB above reserved\n",
selected-&comm, selected-&pid,
selected_oom_score_adj,
selected_tasksize * (long)(PAGE_SIZE / 1024),
current-&comm, current-&pid,
other_file * (long)(PAGE_SIZE / 1024),
minfree * (long)(PAGE_SIZE / 1024),
min_score_adj,
other_free * (long)(PAGE_SIZE / 1024));
trace_lowmem_kill(selected,
other_file, minfree, min_score_adj, other_free);
lowmem_deathpending_timeout = jiffies + HZ;
send_sig(SIGKILL, selected, 0);
//发送kill signal 去kill selected的process
set_tsk_thread_flag(selected, TIF_MEMDIE);
rem -= selected_
以上就是正常的依次 触发lowmemorykill 回收策略流程,驱动比较灵活,还提供了策略阀门值动态修改的机制,通过file ops 让application层去写入修改。
上面有贴出文件节点代码 分别对应为
实际路径为:
同样application 那边设置下来的话 也是需要通过 lowmem_oom_adj_to_oom_score_adj 去转换之后 赋值到 策略数组 lowmem_adj 中,需要注意的是 driver中定义的数组size 为 6 。
application层的接口还是放在上面说到过的 ProcessList.java
中,贴出相关的定义和函数吧,具体流程还是得看代码:
private final int[] mOomAdj = new int[] {
FOREGROUND_APP_ADJ, VISIBLE_APP_ADJ, PERCEPTIBLE_APP_ADJ,
BACKUP_APP_ADJ, CACHED_APP_MIN_ADJ, CACHED_APP_MAX_ADJ
private final int[] mOomMinFreeLow = new int[] {
12288, 18432, 24576,
36864, 43008+20000, 49152+20000
private final int[] mOomMinFreeHigh = new int[] {
73728, 92160, 110592,
129024, 147456+20000, 184320+20000
private final int[] mOomMinFree = new int[mOomAdj.length];
上面为定义的 策略adj 以及minfree 相关的数组资源
private void updateOomLevels(int displayWidth, int displayHeight, boolean write) {
if (write) {
ByteBuffer buf = ByteBuffer.allocate(4 * (2*mOomAdj.length + 1));
buf.putInt(LMK_TARGET);
for (int i=0; i&mOomAdj. i++) {
buf.putInt((mOomMinFree[i]*1024)/PAGE_SIZE);
buf.putInt(mOomAdj[i]);
writeLmkd(buf);
SystemProperties.set("sys.sysctl.extra_free_kbytes", Integer.toString(reserve));
}// 同上面提到的setoomadj 一样,最终的设置由lmkd service 去实现
lmkd service 中对应的command LMK_TARGET 函数为:
static void cmd_target(int ntargets, int *params) {
for (i = 0; i & lowmem_targets_ i++) {
char val[40];
strlcat(minfreestr, ",", sizeof(minfreestr));
strlcat(killpriostr, ",", sizeof(killpriostr));
snprintf(val, sizeof(val), "%d", lowmem_minfree[i]);
strlcat(minfreestr, val, sizeof(minfreestr));
snprintf(val, sizeof(val), "%d", lowmem_adj[i]);
strlcat(killpriostr, val, sizeof(killpriostr));
writefilestring(INKERNEL_MINFREE_PATH, minfreestr);
writefilestring(INKERNEL_ADJ_PATH, killpriostr);
大体脉络理清,运行机制也清晰了,具体的实现细节就需要细读code了
而我碰到的问题,就是memory 不足 触发了lowmemorykiller,但是运行的apk 多进程时 ,最初的进程已经进入后台,compute adj 优先级较低,此时新开进程申请memory,触发回收,memory free 达到lowmemorykill的阀值,直接就杀掉了正在运行apk的后台进程, 不管有没有receiver ,service
而apk如有依赖性 就会触发异常了。
从另一层面上来说,multi process 的apk 对lowmemory device的兼容性存在缺陷,设计并不合理。
作为平台需求,只能从系统的方面来规避了,强提特定的process 的adj 以达到正常运行,但这只是规避~不符合规范
从最近的一些工作来看,碰到了好几次这种存在兼容性问题的apk ,上一篇 32bit/64bit 平台apk动态库的问题 也是这种现象,这还都是 google play 上的apk ,apk的门槛越来越低,都是一味的去追求屌绚酷 ,对深层次的运行机制不去关注,稳定以及运行兼容性自然无法达标,当然这也可以算是google在平台框架兼容性上存在漏洞,贵圈太乱~ ~ 这也是android 无法追上apple的一个原因之一吧~
个人吐槽~请笑看
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:224515次
积分:3545
积分:3545
排名:第6632名
原创:97篇
转载:31篇
评论:104条
阅读:16497
阅读:20006
阅读:21741
(1)(1)(2)(2)(1)(3)(1)(2)(2)(4)(2)(2)(3)(6)(1)(3)(4)(2)(7)(6)(9)(8)(5)(9)(3)(3)(7)(4)(2)(3)(5)(5)(11)

我要回帖

更多关于 android low memory 的文章

 

随机推荐