前言

OOM_ADJ (Out of Memory Adjustment)是android系统在内存不足情况下进行内存调整的重要参数。在处理app启动速度的时候,可以设置主线程的优先级,保证主线程占用的cpu足够久。进程的oom_adj,决定了当内存不够的时候,lmk会根据oom_adj的大小依次释放内存。在前面介绍Activity页面启动路程过程中见到了更新adj的相关方法,但是没有深入介绍,这里分析一些相关实现。

更新adj

final boolean realStartActivityLocked(ActivityRecord r,ProcessRecord app, boolean andResume, boolean checkConfig)throws RemoteException {r.startFreezingScreenLocked(app, 0);//更新LurmService.updateLruProcessLocked(app, true, null);//更新ADJmService.updateOomAdjLocked();xxxx//通过Binder 远程调用Activity的onCreate onResume等生命周期app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),r.compat, r.task.voiceInteractor, app.repProcState, r.icicle, r.persistentState,results, newIntents, !andResume, mService.isNextTransitionForward(),profilerInfo);return true;
}

在启动页面的流程中存在一个名为realStartActivityLocked的方法,这个方法会通过Binder 远程调用Activity的onCreate,onResume 等生命周期方法,在回调生命周期之前调用了updateLruProcessLocked以及updateOomAdjLocked 这两个方法。这两个方法都与进程的优先级有关系。

updateLruProcessLocked

 final void updateLruProcessLocked(ProcessRecord app, boolean activityChange,ProcessRecord client) {//hasActivity用来表示某个app中是否包含activity组件//1.app本身确实包含activity组件;//2\. app本身有service,并且有另外一个含有activity的app链接到此app的service上;//3\. 该app启动serivce的时候带有标记BIND_TREAT_LIKE_ACTIVITY。final boolean hasActivity = app.activities.size() > 0 || app.hasClientActivities|| app.treatLikeActivity;//目前,并没有考虑进程中是否含有Service//因此,虽然理论上定义了Service相关的进程分类,但并没有实现对应的管理策略//在以下代码中,hasService一直为falsefinal boolean hasService = false; // not impl yet. app.services.size() > 0;if (!activityChange && hasActivity) {// The process has activities, so we are only allowing activity-based adjustments// to move it.  It should be kept in the front of the list with other// processes that have activities, and we don't want those to change their// order except due to activity operations.return;}//计数器,记录该函数被调用了多少次,也就是LRU被更新了多少次。mLruSeq++;final long now = SystemClock.uptimeMillis();app.lastActivityTime = now;// First a quick reject: if the app is already at the position we will// put it, then there is nothing to do.if (hasActivity) {final int N = mLruProcesses.size();//如果要插入的app已经在mLruProcesses顶端了,就不用插入了if (N > 0 && mLruProcesses.get(N-1) == app) {if (DEBUG_LRU) Slog.d(TAG, "Not moving, already top activity: " + app);return;}} else {//将其插入到Service 的开头if (mLruProcessServiceStart > 0&& mLruProcesses.get(mLruProcessServiceStart-1) == app) {if (DEBUG_LRU) Slog.d(TAG, "Not moving, already top other: " + app);return;}}int lrui = mLruProcesses.lastIndexOf(app);// persistent app,这部分app不会被杀死,永远在运行,//if (app.persistent && lrui >= 0) {//如果persistent app 已经在列表里面了那么不作处理。// We don't care about the position of persistent processes, as long as// they are in the list.if (DEBUG_LRU) Slog.d(TAG, "Not moving, persistent: " + app);return;}//lrui>=0,说明LRU中之前记录过当前进程的信息//即该进程不是新创建的//那么在调整之前,需要先将之前的记录删除if (lrui >= 0) {if (lrui < mLruProcessActivityStart) {//此进程没有包含ActivitymLruProcessActivityStart--;}if (lrui < mLruProcessServiceStart) {//此进程没有服务,是个其他类型的进程mLruProcessServiceStart--;}//移除进程,后面会再次添加mLruProcesses.remove(lrui);}//nextIndex主要用于记录//当前进程绑定的Service或ContentProvider对应的进程,//应该插入的位置 (对应进程中仅含有Service和Provider时才需要处理)//后文将看到该值的使用情况int nextIndex;if (hasActivity) {final int N = mLruProcesses.size();if (app.activities.size() == 0 && mLruProcessActivityStart < (N-1)) {//该App没有Activity, 但是有一个有Activity的app启动了该App的一个Service。//mLruProcessActivityStart < (N-1) 表示App 不是当前在显示的页面。mLruProcesses.add(N-1, app);//举一个具体的例子,当前显示的App A 打开属于另一个App B的Service,此时当前显示的App A就在//N 这个位置,被打开的Service 所在的App B在N-1 这个位置。// To keep it from spamming the LRU list (by making a bunch of clients),// we will push down any other entries owned by the app.// 下面的代码,是为了调整不同用户之间的公平性;// 当前用户新启动了一个进程,将该用户对应的其它进程,适当往前挪动一下 (优先被kill)final int uid = app.info.uid;// 为了防止某个app中的service绑定了一群client从而导致LRU中顶部大部分都是这些client//,这里需要将这些client往下移动,以防止某些app通过和某个app的service绑定从而提升自己在LRU中位置。for (int i=N-2; i>mLruProcessActivityStart; i--) {ProcessRecord subProc = mLruProcesses.get(i);//遍历找到第一个与app 的uidif (subProc.info.uid == uid) {if (mLruProcesses.get(i-1).info.uid != uid) {//交换i与i-1位置的进程,ProcessRecord tmp = mLruProcesses.get(i);mLruProcesses.set(i, mLruProcesses.get(i-1));mLruProcesses.set(i-1, tmp);i--;}//还是以上面那个例子为例。 A 在打开B之后有打开另一个App C 的Service。//此时 A,B,C 的位置是 N,N-1,N-2 ,由于B C的uid 一样,//此时B也就是先打开的服务可能会一直向后移动直到mLruProcessActivityStart这个位置,} else {// A gap, we can stop here.break;}}} else {// Process has activities, put it at the very tipsy-top.if (DEBUG_LRU) Slog.d(TAG, "Adding to top of LRU activity list: " + app);//进程具有activity,在N位置添加,也就是在栈顶添加,此时app 一般就是要显示的app。mLruProcesses.add(app);}nextIndex = mLruProcessServiceStart;} else if (hasService) {// Process has services, put it at the top of the service list.//不走这个分支,hasService 总是false,if (DEBUG_LRU) Slog.d(TAG, "Adding to top of LRU service list: " + app);mLruProcesses.add(mLruProcessActivityStart, app);nextIndex = mLruProcessServiceStart;mLruProcessActivityStart++;} else  {// Process not otherwise of interest, it goes to the top of the non-service area.// 一般走这里,int index = mLruProcessServiceStart;//一般情况下client == null, 这个分支不走if (client != null) {//client 表示一个另一个进程,此进程可能具有页面,也可没有,但是这个进程打开了//一个只有服务得进程,那么只有服务的进程需要排在client进程的下面// If there is a client, don't allow the process to be moved up higher// in the list than that client.int clientIndex = mLruProcesses.lastIndexOf(client);if (DEBUG_LRU && clientIndex < 0) Slog.d(TAG, "Unknown client " + client+ " when updating " + app);if (clientIndex <= lrui) {// Don't allow the client index restriction to push it down farther in the// list than it already is.clientIndex = lrui;}if (clientIndex >= 0 && index > clientIndex) {//此时表示client 也是一个只有服务的进程而且client在app进程的下面,此时需要//调整添加app进程的位置,调整之后app的位置是clientIndex,client的位置是clientIndex+1index = clientIndex;}}if (DEBUG_LRU) Slog.d(TAG, "Adding at " + index + " of LRU list: " + app);//添加进程mLruProcesses.add(index, app);nextIndex = index-1;mLruProcessActivityStart++;mLruProcessServiceStart++;}// If the app is currently using a content provider or service,// bump those processes as well.//本进程打开了service或者是ContentProvider,如果这个Service或者ContentProvider// 是定义自己App 里面那么此处没啥影响。如果是定义在另一个App里面则有影响。//这里的微调分为两种情况://第一是service所在的进程的位置调整到本进程之后,//第二是将ContentProvider所在的进程位置调整到本进程之后。//调整的方式都是使用updateLruProcessInternalLocked方法,for (int j=app.connections.size()-1; j>=0; j--) {ConnectionRecord cr = app.connections.valueAt(j);if (cr.binding != null && !cr.serviceDead && cr.binding.service != null&& cr.binding.service.app != null&& cr.binding.service.app.lruSeq != mLruSeq&& !cr.binding.service.app.persistent) {nextIndex = updateLruProcessInternalLocked(cr.binding.service.app, now, nextIndex,"service connection", cr, app);}}for (int j=app.conProviders.size()-1; j>=0; j--) {ContentProviderRecord cpr = app.conProviders.get(j).provider;if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq && !cpr.proc.persistent) {nextIndex = updateLruProcessInternalLocked(cpr.proc, now, nextIndex,"provider reference", cpr, app);}}}    private final int updateLruProcessInternalLocked(ProcessRecord app, long now, int index,String what, Object obj, ProcessRecord srcApp) {//srcApp 打开 app 的一个Service 或者ContentProviderapp.lastActivityTime = now;//如果有Activity,不做调整if (app.activities.size() > 0) {// Don't want to touch dependent processes that are hosting activities.return index;}//如果进程不在mLruProcess中,就返回int lrui = mLruProcesses.lastIndexOf(app);if (lrui < 0) {Slog.wtf(TAG, "Adding dependent process " + app + " not on LRU list: "+ what + " " + obj + " from " + srcApp);return index;}//如果进程的位置高于需要调整的位置,不做调整if (lrui >= index) {// Don't want to cause this to move dependent processes *back* in the// list as if they were less frequently used.return index;}//如果目前进程的位置比mLruProcessActivityStart还要高,不调整if (lrui >= mLruProcessActivityStart) {// Don't want to touch dependent processes that are hosting activities.return index;}//走到这里表示lrui<index&&lrui<mLruProcessActivityStart.//把App调整到index-1的位置mLruProcesses.remove(lrui);if (index > 0) {index--;}if (DEBUG_LRU) Slog.d(TAG, "Moving dep from " + lrui + " to " + index+ " in LRU list: " + app);//mLruProcesses.add(index, app);return index;}// 例如 当前显示的App  A打开了一个App B 的一个Service ,由于App  A 是当前显示的App,优先级最高,//此时A 使用的Service 所在的App B 也应该尽可能的提高等级避免内存回收,此时会将App B 放到mLruProcessServiceStart 这个位置。//假如非得回收内存的话会先回收0-mLruProcessServiceStart 之间的进程占据的内存。

mLruProcesses 是一个列表,其本分为三个部分 0–mLruProcessServiceStart 用于保存其他进程;

mLruProcessServiceStart – mLruProcessActivityStart 用于保存服务进程,但是实际情况下这个区域的大小是0,也即是服务进程实际也是放在了其他进程区域。

mLruProcessActivityStart–end 保存的有Activity的进程。 每次添加Activity 进程都是在end位置,在mLruProcessServiceStart位置添加服务进程或者其他进程。

位置越大的进程优先级越高越不容易被回收。

每次调用updateLruProcessLocked调整某个进程的位置的时候也会调整与之相关的进程的位置,例如调整进程A 的位置 就要顺便调整A 启动的Service 以及ContentProvider 所在的进程位置。

————————————————

版权声明:本文为CSDN博主「昨夜西风在吹」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/qq_31469589/article/details/11796935

以上就是有关Android内存管理ADJ讲解;有关更多Android 开发技术性能调优学习;大家可以点击《Android性能优化手册》获取相关学习

结尾(心灵的鸡汤)

我相信,梦想只要能坚持,就一定能成为现实。就像代表着永恒的天蓝色。就让这小小的梦想的种子,在我们心中,渐渐发芽、成长,在心中开出美丽、绚烂的花。让我们努力飞翔,乘着梦想的翅膀,飞到成功的远方。

Android性能优化OOM内存管理——ADJ相关推荐

  1. Android进阶——性能优化之内存管理机制和垃圾采集回收机制(六)

    文章大纲 引言 一.内存泄漏和内存溢出概述 二.Java运行时内存模型 1.线程私有数据区 1.1.程序计数器PC 1.2.虚拟机栈 1.3 本地方法栈 2.所有线程共享数据区 2.1.Java堆 2 ...

  2. Android 系统性能优化(55)---Android 性能优化之内存优化

    Android 性能优化之内存优化 前言 Android App优化这个问题,我相信是Android开发者一个永恒的话题.本篇文章也不例外,也是来讲解一下Android内存优化.那么本篇文章有什么不同 ...

  3. Android 性能优化之内存泄漏检测以及内存优化(上)

    在 Java 中,内存的分配是由程序完成的,而内存的释放则是由 Garbage Collecation(GC) 完成的,Java/Android 程序员不用像 C/C++ 程序员一样手动调用相关函数来 ...

  4. Android性能优化之内存优化 1

    导语 智能手机发展到今天已经有十几个年头,手机的软硬件都已经发生了翻天覆地的变化,特别是Android阵营,从一开始的一两百M到今天动辄4G,6G内存.然而大部分的开发者观看下自己的异常上报系统,还是 ...

  5. Android 性能优化之内存泄漏,使用MATLeakCanary解决问题

    本文授权发布公众号[刘桂林],星球[Hi Android] App进行到最终的测试的时候,往往会出现一些性能上,以及内存上的问题,需要优化,这也是一个Android高级工程师所需要了解并且掌握的知识点 ...

  6. Android面试-Android性能优化和内存优化、APP启动速度一线大厂的实战案例解析

    一.Android 内存管理机制 二.优化内存的意义 三.避免内存泄漏 四.优化内存空间 五.图片管理模块的设计与实现 六.总结 深入探索Android内存优化 第一章.重识内存优化 第二章.常见工具 ...

  7. Android性能优化之内存篇

    2019独角兽企业重金招聘Python工程师标准>>> Google近期在Udacity上发布了Android性能优化的在线课程,分别从渲染,运算与内存,电量几个方面介绍了如何去优化 ...

  8. android—性能优化2—内存优化

    文章目录 性能优化: 工具: memory profiler LeakCanary arthook epic 库 java内存管理机制 java 内存回收机制 Android内存管理机制 Dalvik ...

  9. Android性能优化之内存篇(三)

    原文链接:http://hukai.me/android-training-managing_your_app_memory/ http://hukai.me/android-performance- ...

最新文章

  1. windows环境下32位汇编语言程序设计 90盘_Python 0基础详细教程 环境安装01
  2. 【C++基础】++i和i++
  3. 机器学习-特征处理/归一化/标准化/降维03
  4. php作品答辩问问题,一般答辩会问到什么问题
  5. neon浮点运算_Linux下VFP NEON浮点编译
  6. 将具体处理交给子类——模板方法模式
  7. 【Flutter】基础组件【07】Appbar
  8. java矩形类_Java定义矩形类
  9. 例如微博表情添加到textView中
  10. 反函数抽样(包括离散的)
  11. 小米手机扩容教程_手机内存不够怎么办?扩容实记教给你 16G秒变64G
  12. 我用python做了个测词汇量的小工具
  13. Python数据分析(Pandas)
  14. cad修改快捷键_CAD教程:CAD建筑户型图纸还能这么画?
  15. 大数据时代,数据实时同步解决方案的思考—最全的数据同步总结
  16. Python Tutorial中英双语对照文档5
  17. blackduck issue fix
  18. linux查看riak版本,riak源码阅读手记 压力测试
  19. 不同vlan间的通信--三层交换技术
  20. 拼音韵母有哪些 单复韵母有哪些

热门文章

  1. CPUID详解_转载百度
  2. Unity个人开发中的踩坑记录(混沌式更新)
  3. 【Pytest篇】pytest的parametrize之ids参数正文编码问题
  4. LDPC码简介(一)
  5. 【校招面经】阿里巴巴_数据分析岗_面试笔试题
  6. ksxt问题集之——“请求的内容似乎是脚本,因而将无法由静态文件处理程序来处理”
  7. mysql dba系统学习-数据库事务详解
  8. curl -sSL https://bit.ly/2ysbOFE | bash -s无法执行问题解决
  9. 第一部分-实时爬取WeiBo热搜
  10. 一文读懂网络通信技术原理