范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

Android性能优化OOM内存管理ADJ

  前言
  OOM_ADJ (Out of Memory Adjustment)是android系统在内存不足情况下进行内存调整的重要参数。在处理app启动速度的时候,可以设置主线程的优先级,保证主线程占用的cpu足够久。进程的oom_adj,决定了当内存不够的时候,lmk会根据oom_adj的大小依次释放内存。在前面介绍Activity页面启动路程过程中见到了更新adj的相关方法,但是没有深入介绍,这里分析一些相关实现。 更新adjfinal boolean realStartActivityLocked(ActivityRecord r,         ProcessRecord app, boolean andResume, boolean checkConfig)         throws RemoteException {      r.startFreezingScreenLocked(app, 0);      //更新Lur     mService.updateLruProcessLocked(app, true, null);     //更新ADJ     mService.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一直为false         final 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) {                 //此进程没有包含Activity                 mLruProcessActivityStart--;             }             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 的uid                     if (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+1                     index = 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 或者ContentProvider               app.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 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性能优化手册》 获取相关学习资料。 结尾(心灵的鸡汤)
  我相信,梦想只要能坚持,就一定能成为现实。就像代表着永恒的天蓝色。就让这小小的梦想的种子,在我们心中,渐渐发芽、成长,在心中开出美丽、绚烂的花。让我们努力飞翔,乘着梦想的翅膀,飞到成功的远方。

三季度快递服务满意度公布,这家快递排名第一近日,国家邮政局发布关于2022年第三季度快递服务满意度调查和时限准时率测试结果的通告,该季度快递企业公众满意度品牌前五名分别是京东快递顺丰邮政中通圆通。据了解,本次调查对象为20翌圣生物科创板首发将于11月25日上会中证网讯(王珞)上交所消息,翌圣生物科创板首发将于11月25日上会。公司拟公开发行不超过2,103。35万股(不含采用超额配售选择权发行的股份数量),募资110,855。23万元,油价调整消息今天11月22日,下调后国内929598号汽油售价经历了近半个月的等待,油价调价窗口终于在今天凌晨打开,结果也是车主们期待的样子,由于这次油价统计周期结束时,原油均价录得89。75美元桶,和上次油价统计相比变化率为2。56,因此对提高警惕!大范围雨雪越来越凶,权威预报或大暴雪大暴雨一起来11月21日下午,从风云四号高清可见光卫星云图上看,在孟加拉湾和南海两个热带气旋胚胎的联手助力下,大量水汽正涌入我国中东部。因此,在充沛的暖湿水汽支持下,中东部的阴雨云系应声扩大,韩国爱豆登上世界杯,疑似土豪为了女儿追星,才请田柾国参加卡塔尔足球世界杯开幕,开幕式上有不少明星,比如摩根弗里曼。85岁的他身穿西装,左手戴着手套,不少网友说看上去像假手。后来他把手套摘了,整个手掌是向内弯曲的,据悉,摩根弗里曼曾遭遇车书房忆别薛中锐一个让人想起来说起来都眼含热泪的人11月21日,山东省话剧院发布讣告,著名话剧影视表演朗诵艺术家薛中锐因病医治无效,于11月20日19时01分在济南去世,享年85周岁。遗体告别仪式定于11月24日14时在济南市殡仪交易预测!火箭1换4梅尔顿太阳3换1库兹马,湖人2换1伯克斯来看看美国媒体fanspo的三笔交易预测。火箭1换4梅尔顿。方案火箭送出戈登,得到梅尔顿科尔克马兹塞布尔和一个二轮签。不出所料,火箭主教练塞拉斯在输给步行者后公开强调了小波特的重要世界杯文明观赛倡议书2022年卡塔尔世界杯开幕在即,这是四年一度广大球迷翘首以盼的体育盛宴。今年6月,抖音集团成为2022年卡塔尔世界杯持权转播商中央广播电视总台直播战略合作伙伴。因此,球迷朋友可以在大崩盘!韩乒猛将14惨败,张本智和夺冠,林高远王楚钦颗粒无收11月19日,亚洲杯男单决赛落下帷幕,19岁的张本智和41打败韩国猛将林仲勋,夺得冠军,在国乒主力参赛的情况下,张本夺冠,十分罕见。此次亚洲杯,国乒派出了王楚钦和林高远参赛,遗憾的iPhone耗电异常的问题,我终于找到了主要原因iPhone14Pro耗电问题经常看我文章的朋友应该知道,我的iPhone14Pro在到手后一直存在严重的耗电异常问题。白天续航非常差,即使是我这种不玩游戏,只轻度使用的情况下,依事件驱动架构需要避开的5大陷阱作者以码为梯排版以码为梯文章字数2972本文是一篇个人觉得比较好的英文博客的译文,希望大家有所收获事件驱动架构通过引入消息中间件,使其具备了低耦合(decouple),易扩展(sc
女死刑犯在最后一晚,都做些什么事?女死刑犯在最后一晚,又可以做些什么。除了整晚辗转反侧,沉默寡言,喃喃自语,还能怎么样,生命的权利以不掌握在自己手中,当初的残忍血腥,在这一刻唤醒泯灭人性的良知,但手铐脚缭以牢牢套着衢州房价会跌吗?跌的概率是很大的,必尽衢州人均收入跟房价是不成正比的,衢州本地人口就几十万等级,也就4线城市,衢州外来人口又不多,本区域又没有大的产业经济支撑,西区房子都跟航埠接上了,整体房子空置农民工没有社保,都不愿个人缴费以后怎么办,如果个人缴费划算吗?社保是缴才有,不缴就没有。这是社保法规定的。自己不愿意缴,以后要自己想办法,伸手要办不到。自己缴还是划算的,可以享受国家的补贴,不缴享受不到。不愿意交就没有社保呗,有啥啊划算?那要跟邹扶澜老师视频自学欧楷一年半多了,现在感觉不到进步了,该怎么办?跟邹扶澜的视频练习书法写成这样已经很好了,写的都比邹扶澜好了,比邹的欧体写的还纯正呢,再跟着学下去当然就没有进步了,写成这样了就不用再看邹扶澜的视频了,赶紧关掉视频吧。客观来说,邹评职称时优秀班集体对普通老师有用吗?评职称时优秀班集体有用没用,关键看你们单位职称评审方案是如何界定的。如果评审方案有这方面的规定,那就可以给加分。如果没涉及到就不可能给加分了。首先,优秀班集体是集体荣誉,不是个人荣什么情况下,子女不能当兵,考公务员?我国法律法规,无论当兵还是考公务员,都是需要政审的,而且政审审查的就是三代内的直系亲属的政治问题。不管父母因为何种原因,触犯了法律,被判刑坐牢,那么子女当兵或者是考公务员都是过不了从十元钱解决看病难,到一百八十一元一人的新农合还值不值得交这个钱?2018年的新农合费用已经开始征收了,相比2017年,2018年的新农合会有较明显的涨幅,多数地区都已经从2016年的150元每人上涨到了180元每人。当然,由于各地区新农合的缴费彩票怎样买中奖率高?中奖简单,中大奖很难。我以前经常买彩票,摸索出一点小窍门,给大家分享。虽然中不了大奖,但是不会赔很多。以提主所说的福利彩票双色球为例。双色球的玩法是从33个红球中选择6个,从16个航空乘务员的年薪加年终奖,一年是多少,福利又是多少呢?这个问题比较笼统了,航空乘务员内部也是分很多级别的,甚至其中还有拿年薪的领导阶层,同时不同的航空公司计算方式还略有不同。咱就不讨论刚入职以及那些拿年薪平均小时的领导阶层了。入职五年打算读博的话,研究生毕业学校重要吗?读博有三种方式,一是考博,二是硕博连读,三是直博。想要读博士研究生毕业学校重要吗?如果是考博的话,研究生毕业院校有一定的影响,但如果是硕博连读,那研究生毕业学校没有什么影响。考博与有的退休老人的退休金八九千元,为什么消费的时候不敢大手大脚?谢邀请,有多种原因在内,当年过的穷日子,有些害怕,也有的省吃俭用养成习惯,有的为了以后身体有个疾病,准备治疗底垫,加上消费观念不同,真的有钱不敢花不敢用,抠门过日子是他们的优良传统