应用办公生活信息教育商业
投稿投诉
商业财经
汽车智能
教育国际
房产环球
信息数码
热点科技
生活手机
晨报新闻
办公软件
科学动态
应用生物
体育时事

Android性能优化OOM内存管理ADJ

  前言
  OOMADJ(OutofMemoryAdjustment)是android系统在内存不足情况下进行内存调整的重要参数。在处理app启动速度的时候,可以设置主线程的优先级,保证主线程占用的cpu足够久。进程的oomadj,决定了当内存不够的时候,lmk会根据oomadj的大小依次释放内存。在前面介绍Activity页面启动路程过程中见到了更新adj的相关方法,但是没有深入介绍,这里分析一些相关实现。更新adjfinalbooleanrealStartActivityLocked(ActivityRecordr,ProcessRecordapp,booleanandResume,booleancheckConfig)throwsRemoteException{r。startFreezingScreenLocked(app,0);更新LurmService。updateLruProcessLocked(app,true,null);更新ADJmService。updateOomAdjLocked();xxxx通过Binder远程调用Activity的onCreateonResume等生命周期app。thread。scheduleLaunchActivity(newIntent(r。intent),r。appToken,System。identityHashCode(r),r。info,newConfiguration(mService。mConfiguration),r。compat,r。task。voiceInteractor,app。repProcState,r。icicle,r。persistentState,results,newIntents,!andResume,mService。isNextTransitionForward(),profilerInfo);returntrue;}
  在启动页面的流程中存在一个名为realStartActivityLocked的方法,这个方法会通过Binder远程调用Activity的onCreate,onResume等生命周期方法,在回调生命周期之前调用了updateLruProcessLocked以及updateOomAdjLocked这两个方法。这两个方法都与进程的优先级有关系。updateLruProcessLockedfinalvoidupdateLruProcessLocked(ProcessRecordapp,booleanactivityChange,ProcessRecordclient){hasActivity用来表示某个app中是否包含activity组件1。app本身确实包含activity组件;2。app本身有service,并且有另外一个含有activity的app链接到此app的service上;3。该app启动serivce的时候带有标记BINDTREATLIKEACTIVITY。finalbooleanhasActivityapp。activities。size()0app。hasClientActivitiesapp。treatLikeActivity;目前,并没有考虑进程中是否含有Service因此,虽然理论上定义了Service相关的进程分类,但并没有实现对应的管理策略在以下代码中,hasService一直为falsefinalbooleanhasServicefalse;notimplyet。app。services。size()0;if(!activityChangehasActivity){Theprocesshasactivities,soweareonlyallowingactivitybasedadjustmentstomoveit。Itshouldbekeptinthefrontofthelistwithotherprocessesthathaveactivities,andwedontwantthosetochangetheirorderexceptduetoactivityoperations。return;}计数器,记录该函数被调用了多少次,也就是LRU被更新了多少次。mLruSeq;finallongnowSystemClock。uptimeMillis();app。lastActivityTimenow;Firstaquickreject:iftheappisalreadyatthepositionwewillputit,thenthereisnothingtodo。if(hasActivity){finalintNmLruProcesses。size();如果要插入的app已经在mLruProcesses顶端了,就不用插入了if(N0mLruProcesses。get(N1)app){if(DEBUGLRU)Slog。d(TAG,Notmoving,alreadytopactivity:app);return;}}else{将其插入到Service的开头if(mLruProcessServiceStart0mLruProcesses。get(mLruProcessServiceStart1)app){if(DEBUGLRU)Slog。d(TAG,Notmoving,alreadytopother:app);return;}}intlruimLruProcesses。lastIndexOf(app);persistentapp,这部分app不会被杀死,永远在运行,if(app。persistentlrui0){如果persistentapp已经在列表里面了那么不作处理。Wedontcareaboutthepositionofpersistentprocesses,aslongastheyareinthelist。if(DEBUGLRU)Slog。d(TAG,Notmoving,persistent:app);return;}lrui0,说明LRU中之前记录过当前进程的信息即该进程不是新创建的那么在调整之前,需要先将之前的记录删除if(lrui0){if(lruimLruProcessActivityStart){此进程没有包含ActivitymLruProcessActivityStart;}if(lruimLruProcessServiceStart){此进程没有服务,是个其他类型的进程mLruProcessServiceStart;}移除进程,后面会再次添加mLruProcesses。remove(lrui);}nextIndex主要用于记录当前进程绑定的Service或ContentProvider对应的进程,应该插入的位置(对应进程中仅含有Service和Provider时才需要处理)后文将看到该值的使用情况intnextIndex;if(hasActivity){finalintNmLruProcesses。size();if(app。activities。size()0mLruProcessActivityStart(N1)){该App没有Activity,但是有一个有Activity的app启动了该App的一个Service。mLruProcessActivityStart(N1)表示App不是当前在显示的页面。mLruProcesses。add(N1,app);举一个具体的例子,当前显示的AppA打开属于另一个AppB的Service,此时当前显示的AppA就在N这个位置,被打开的Service所在的AppB在N1这个位置。TokeepitfromspammingtheLRUlist(bymakingabunchofclients),wewillpushdownanyotherentriesownedbytheapp。下面的代码,是为了调整不同用户之间的公平性;当前用户新启动了一个进程,将该用户对应的其它进程,适当往前挪动一下(优先被kill)finalintuidapp。info。uid;为了防止某个app中的service绑定了一群client从而导致LRU中顶部大部分都是这些client,这里需要将这些client往下移动,以防止某些app通过和某个app的service绑定从而提升自己在LRU中位置。for(intiN2;imLruProcessActivityStart;i){ProcessRecordsubProcmLruProcesses。get(i);遍历找到第一个与app的uidif(subProc。info。uiduid){if(mLruProcesses。get(i1)。info。uid!uid){交换i与i1位置的进程,ProcessRecordtmpmLruProcesses。get(i);mLruProcesses。set(i,mLruProcesses。get(i1));mLruProcesses。set(i1,tmp);i;}还是以上面那个例子为例。A在打开B之后有打开另一个AppC的Service。此时A,B,C的位置是N,N1,N2,由于BC的uid一样,此时B也就是先打开的服务可能会一直向后移动直到mLruProcessActivityStart这个位置,}else{Agap,wecanstophere。break;}}}else{Processhasactivities,putitattheverytipsytop。if(DEBUGLRU)Slog。d(TAG,AddingtotopofLRUactivitylist:app);进程具有activity,在N位置添加,也就是在栈顶添加,此时app一般就是要显示的app。mLruProcesses。add(app);}nextIndexmLruProcessServiceStart;}elseif(hasService){Processhasservices,putitatthetopoftheservicelist。不走这个分支,hasService总是false,if(DEBUGLRU)Slog。d(TAG,AddingtotopofLRUservicelist:app);mLruProcesses。add(mLruProcessActivityStart,app);nextIndexmLruProcessServiceStart;mLruProcessActivityStart;}else{Processnototherwiseofinterest,itgoestothetopofthenonservicearea。一般走这里,intindexmLruProcessServiceStart;一般情况下clientnull,这个分支不走if(client!null){client表示一个另一个进程,此进程可能具有页面,也可没有,但是这个进程打开了一个只有服务得进程,那么只有服务的进程需要排在client进程的下面Ifthereisaclient,dontallowtheprocesstobemoveduphigherinthelistthanthatclient。intclientIndexmLruProcesses。lastIndexOf(client);if(DEBUGLRUclientIndex0)Slog。d(TAG,Unknownclientclientwhenupdatingapp);if(clientIndexlrui){Dontallowtheclientindexrestrictiontopushitdownfartherinthelistthanitalreadyis。clientIndexlrui;}if(clientIndex0indexclientIndex){此时表示client也是一个只有服务的进程而且client在app进程的下面,此时需要调整添加app进程的位置,调整之后app的位置是clientIndex,client的位置是clientIndex1indexclientIndex;}}if(DEBUGLRU)Slog。d(TAG,AddingatindexofLRUlist:app);添加进程mLruProcesses。add(index,app);nextIndexindex1;mLruProcessActivityStart;mLruProcessServiceStart;}Iftheappiscurrentlyusingacontentproviderorservice,bumpthoseprocessesaswell。本进程打开了service或者是ContentProvider,如果这个Service或者ContentProvider是定义自己App里面那么此处没啥影响。如果是定义在另一个App里面则有影响。这里的微调分为两种情况:第一是service所在的进程的位置调整到本进程之后,第二是将ContentProvider所在的进程位置调整到本进程之后。调整的方式都是使用updateLruProcessInternalLocked方法,for(intjapp。connections。size()1;j0;j){ConnectionRecordcrapp。connections。valueAt(j);if(cr。binding!null!cr。serviceDeadcr。binding。service!nullcr。binding。service。app!nullcr。binding。service。app。lruSeq!mLruSeq!cr。binding。service。app。persistent){nextIndexupdateLruProcessInternalLocked(cr。binding。service。app,now,nextIndex,serviceconnection,cr,app);}}for(intjapp。conProviders。size()1;j0;j){ContentProviderRecordcprapp。conProviders。get(j)。provider;if(cpr。proc!nullcpr。proc。lruSeq!mLruSeq!cpr。proc。persistent){nextIndexupdateLruProcessInternalLocked(cpr。proc,now,nextIndex,providerreference,cpr,app);}}}privatefinalintupdateLruProcessInternalLocked(ProcessRecordapp,longnow,intindex,Stringwhat,Objectobj,ProcessRecordsrcApp){srcApp打开app的一个Service或者ContentProviderapp。lastActivityTimenow;如果有Activity,不做调整if(app。activities。size()0){Dontwanttotouchdependentprocessesthatarehostingactivities。returnindex;}如果进程不在mLruProcess中,就返回intlruimLruProcesses。lastIndexOf(app);if(lrui0){Slog。wtf(TAG,AddingdependentprocessappnotonLRUlist:whatobjfromsrcApp);returnindex;}如果进程的位置高于需要调整的位置,不做调整if(lruiindex){Dontwanttocausethistomovedependentprocessesbackinthelistasiftheywerelessfrequentlyused。returnindex;}如果目前进程的位置比mLruProcessActivityStart还要高,不调整if(lruimLruProcessActivityStart){Dontwanttotouchdependentprocessesthatarehostingactivities。returnindex;}走到这里表示lruiindexlruimLruProcessActivityStart。把App调整到index1的位置mLruProcesses。remove(lrui);if(index0){index;}if(DEBUGLRU)Slog。d(TAG,MovingdepfromlruitoindexinLRUlist:app);mLruProcesses。add(index,app);returnindex;}例如当前显示的AppA打开了一个AppB的一个Service,由于AppA是当前显示的App,优先级最高,此时A使用的Service所在的AppB也应该尽可能的提高等级避免内存回收,此时会将AppB放到mLruProcessServiceStart这个位置。假如非得回收内存的话会先回收0mLruProcessServiceStart之间的进程占据的内存。
  mLruProcesses是一个列表,其本分为三个部分0mLruProcessServiceStart用于保存其他进程;
  mLruProcessServiceStartmLruProcessActivityStart用于保存服务进程,但是实际情况下这个区域的大小是0,也即是服务进程实际也是放在了其他进程区域。
  mLruProcessActivityStartend保存的有Activity的进程。每次添加Activity进程都是在end位置,在mLruProcessServiceStart位置添加服务进程或者其他进程。
  位置越大的进程优先级越高越不容易被回收。
  每次调用updateLruProcessLocked调整某个进程的位置的时候也会调整与之相关的进程的位置,例如调整进程A的位置就要顺便调整A启动的Service以及ContentProvider所在的进程位置。
  版权声明:本文为CSDN博主昨夜西风在吹的原创文章,遵循CC4。0BYSA版权协议,转载请附上原文出处链接及本声明。原文链接:https:blog。csdn。netqq31469589articledetails11796935
  以上就是有关Android内存管理ADJ讲解;有关更多Android开发技术性能调优学习;大家私信:手册《Android性能优化手册》获取相关学习资料。结尾(心灵的鸡汤)
  我相信,梦想只要能坚持,就一定能成为现实。就像代表着永恒的天蓝色。就让这小小的梦想的种子,在我们心中,渐渐发芽、成长,在心中开出美丽、绚烂的花。让我们努力飞翔,乘着梦想的翅膀,飞到成功的远方。

高州粤龙山霍比特人村,让误入童话世界的打卡圣地如果你看过《指环王》或《霍比特人》系列电影,你一定会熟悉霍比特人的房子,那是充满童话色彩的场景。不寻常的建筑,对我们许多人来说总是一种幻想,但这种幻想,却让有心人转化为具……勇士一支独秀,西部竞争激烈再起波澜,火箭7连胜,恐成最大黑马NBA常规赛正在激战之中,随着比赛的深入,各球队的排名,也随之发生着巨大的变化。西部更是进入了群雄逐鹿的状态,战绩犬牙交错,竞争进入白热化阶段。勇士一马当先,占据头名……换手型的阵痛依旧存在!格林需要改变心态和进攻的选择在上周一对阵国王队的比赛中,格林用最后的进攻篮板完成了他在第四节唯一一次触球,当时无论是美国当地的记者,球迷,还是虎扑的JR,还是贴吧,各各体育论坛,都对格林底角抽烟接不到球的……李霄鹏遭重击,11分钟手球送点,铁卫强烈不满,主裁吹主场哨?客场对阵日本一战,李霄鹏迎来了执教国足的首场比赛。然而,开场仅仅11分钟,王燊超就因为禁区内手球而送出了点球。李霄鹏的排兵布阵颇有新意,在首发阵容出炉之后,尽管媒体认为国……侠客冰雪冰雪单职业新出炉侠客冰雪手游正式的开新服!全部参加测试的游戏玩家,均可得到丰富好礼!热爱冰雪系类的小伙伴可不能失去了这一次机会!复古时尚的画面风格、操作面板、人物角色页面、招式页面……心碎!丁俊晖810出局一轮游,最大弱点被曝光,连续4年无缘8今天凌晨,斯诺克世锦赛继续进行,最受关注的毫无疑问还是丁俊晖与威尔逊的第2阶段比赛,结果这下半场的比赛,也是打的更加的激烈,两人也是从55一直拿到了88平,最后2局的比赛,丁俊……郭进拴探访终南山郭进拴探访终南山位于秦岭山脉中段的终南山,相距西安市只有25千米,海拔2604米,总面积4851平方千米。地形险阻,道路崎岖,大山深谷,连绵数百里,横亘在陕西中部而拔起。……景甜真的太帅气了,短款皮衣配牛仔裤,格外的时髦个性如果说有什么单品是混搭界的天花板,那自带酷帅气息的皮衣自然要占据重要位置,毕竟皮革质感与多种风格相结合,不论是时尚感还是设计感都可以说是玩味十足,更能让你在甜酷之间自由切换,轻……5月青年失业率高达18。4,专家称失业率畸高不会是常态疫情的影响到底有多大?过去的几年里,疫情爆发时的影响远远不如2022年的严重,目前疫情已经导致全球经济下滑,全球通货膨胀加剧,国内更是从年初开始出现了大厂裁员潮。今……2013年,孟加拉的44亿美元工程,24国均退出竞标,为何中回首以往,中国曾经历过一段积贫积弱的阶段,历史的经验告诉我们:弱国无外交,在上世纪新中国刚刚成立之际,就连建一座钢架桥都是十分困难的事情。为此,中国不得不斥巨资引进外国人才和相……逆水寒28个年度大瓜被当成了考试题?玩家看一眼题我都懵了网络游戏是一个小社会,在这里,人情冷暖和爱恨情仇才是很多玩家难以割舍的关键,尤其是那些画面表现出色深受妹子喜爱的古风网游,更是逼一般直男遍地走的游戏多了许多爱恨别离的狗血故事。……TPLINK推出XDR6020易展版无线路由器首发479元,IT之家1月1日消息,TPLINK近日推出了XDR6020易展版无线路由器,支持WiFi6AX6000规格,拥有8根天线。这款产品零售价529元,预售期间到手价低至479元,将……
82。3440。7!低配版特纳,可惜湖人不识货2年5800万,续约意味着短期内,步行者不会再考虑交易迈尔斯特纳了。生涯至今的477场比赛,场均13。2分6。8篮板2。3封盖,两分命中率54。8(场均4。0球)、三分命……一口软糯香甜还带着芝麻香!原来这道普普通通的食材还能这么做如果要盘点山药必做的食谱,那这款豆沙饼必须拥有名字,松软香甜,老少都适宜,而且自己做的没有任何添加剂,家人吃着安全且放心,口感比起其他的小饼也丝毫不逊色!用红豆沙做内馅,给山药……赏兔灯买年货浙江宁波多种形式迎佳节央视网消息:在浙江宁波,人们赏兔灯、买年货,以各种形式迎佳节,浓浓的年味也扑面而来。这两天,余姚阳明古镇的兔年民俗灯展陆续亮灯。夜幕降临,一组组花灯亮起,把古镇装扮得流光……目标明确!雷军小米汽车明年量产争取1520年进入世界前五,网中国经济周刊经济网讯自2021年3月官宣以来,小米持续加大造车投入,吸引了不少业界的目光。最新消息显示,2月9日晚,在小米投资者日上,小米CEO雷军分享了小米造车的最新进展。……1米9女排王一梅,退役6年瘦了不少,不愁工作,35岁仍未婚中国女排实力强大,80年代曾经实现过世界大赛的5连冠。此后虽然经历过低谷和蛰伏,但04年雅典奥运会重回巅峰,16年里约奥运会再度登顶,都让球迷看到了女排的竞争精神。纵观女排历史……即时配送进入分钟级时代,配送员保障几何?即时配送行业蓬勃发展的同时出现了存在交通隐患、工伤保障覆盖有限等问题。专家建议建立广覆盖的职业风险共同体,国家发改委拟出台政策促进行业健康有序发展。2月9日中午,在北京市朝阳区……铝型材领先企业,鑫铂股份光伏及汽车轻量化驱动成长(报告出品方分析师:东亚前海证券郑倩怡)1。聚焦铝型材领域,公司业绩大幅增长1。1。铝型材行业龙头,大力发展光伏新能源铝型材业务公司是国内铝型材龙头企业之一。……跟着非遗大师过大年!当民俗文化遇见禁毒宣传逛庙会、赏花灯、猜灯谜是正月十五元宵节的传统活动。江苏省南京市秦淮区禁毒办抓住这一有利时机,在第37届中国秦淮灯会主会场5A级国家景区南京夫子庙开展民俗文化禁毒街区宣传活动。本……穿对皮草能有多高级?学潮人这样搭,回头率高还时髦显瘦皮草外套的搭配在近几年的时尚圈内真的是属于非常热门和时髦的单品存在的,而如果是对于本身不会穿皮草的女性而言,其实更多的可能性是会将皮草的搭配呈现的土气和不高级,甚至是没有任何优……绘本故事最好的朋友如何建立和维护友谊?今日绘画故事《最好的朋友》对任何年龄段的人而言,朋友都是人生存在的核心。朋友拓宽我们的经验,让我们了解自己全部的能力技能、善良、公正、同情心、气度,并最终让我们明白自他们……新年穿红更喜庆!双十二提前BUY爱慕内衣在中国传统文化中,凤凰与梧桐常常用于表达吉祥祝福的意象凤凰于飞,梧桐花开;喜从天降,福运成双。爱慕将传统纹样融入现代设计理念,呈现不一样的新年红内衣,冬季特别推出好事将近系列,……微型世界里的变形金刚童话景观化学元素创造了自然的奇迹,他们纯净的单质样品超乎想象,有的棱角分明、方正成型,就像变形金刚;有的细腻叠生、千变万化,犹如童话世界里创造的不可思议的景象奇观。《美丽的化学元……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网