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

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性能优化手册》 获取相关学习资料。 结尾(心灵的鸡汤)
  我相信,梦想只要能坚持,就一定能成为现实。就像代表着永恒的天蓝色。就让这小小的梦想的种子,在我们心中,渐渐发芽、成长,在心中开出美丽、绚烂的花。让我们努力飞翔,乘着梦想的翅膀,飞到成功的远方。

查干湖冬捕再刷纪录,一网拉出50万斤,为何能做到年年大丰收?说起查干湖,于我们而言,印象最为深刻的当然属它的冬捕盛况了。每年的12月26日开始,就是查干湖最为热闹的时候,这也是查干湖冬捕的开始。此时的查干湖不仅渔民热火朝天的准备,同时也能吸俄罗斯美女在中国边境小城卖力赚钱,直言中国更像老家?众所周知,俄罗斯女性们都有着金发碧眼,高挑性感的身材。正是由于俄罗斯当地有着遍地如云的美女们,这里也就成为了我国多数男性游客们出国旅游的首选地了。(此处已添加小程序,请到今日头条客外地人去海南过冬,去哪个城市比较温暖?一不小心选错城市太冷了长年无冬,温暖如春,面朝大海,春暖花开。这是你认识的海南。但是,来过之后,你会发现,真实的海南,可能比你的老家还冷。很多人第一次到海南过冬,以为找房子才是重点。殊不知选错城市才是最政策大变!未来看好的方向关于新十条,权威解读看这里新十条有关政策,进一步减少出行限制,不再开展落地检,大部分场所不需要核酸证明和健康码了。就拿我自己来说,目前已经7天没做核酸了。这意味着投资策略也要发生改累了吗?停下脚步,喝点鸡汤吧感想人生是一个很漫长的过程,在不同的人生阶段,在不同的时代,本身就会有不一样的内容。所以去接受失败就此摆烂,还是调整心态重新起航,没有对错可言。关键在于你选择什么,那就坚持什么!失游在乌镇的故事(三)冬日生活打卡季纵然是在雨中,但乌镇依旧美的炫目。深褐色的木桥栏杆旁,笔直的水杉耸立,间或有鸡爪械的红叶印衬着,红的耀眼绿的深沉,一如穿城而过的运河,悠悠地唱着古老韵味的歌,牵连着厚英吉沙县旅游景点有哪些?英吉沙县英吉沙县旅游景点有穆孜鲁克湿地公园英吉沙国家湿地公园英吉沙县土陶村景区英吉沙古城墙英吉沙县北湖公园英吉沙古街新疆英吉沙萨罕国家沙漠公园英吉沙县南湖旅游度假区英吉沙县文化馆英贝莱德2023年能源股和医疗保健股机会最大过去40年的大稳健时期已经结束,我们将进入一个新时期。全球最大的资产管理公司贝莱德(BlackRock)认为,2023年投资者需要制定新的投资策略。贝莱德投资研究所(BII)负责人买手机建议一步到位,目前只有这3款手机符合要求,能用到2025年买手机建议一步到位,目前只有这3款手机符合要求,能用到2025年。真我GT大师探索版配置CPU搭载骁龙870处理器LPDDR4XUFS3。1屏幕三星E3柔性曲面屏,支持1080P分河南7村3镇(乡)入选全国乡村旅游重点村镇(乡)近日,文化和旅游部国家发展改革委联合开展全国乡村旅游重点村镇遴选推荐工作,确定了第四批200个全国乡村旅游重点村和第二批98个全国乡村旅游重点镇(乡)名单。河南省济源市承留镇花石村智能手机可能被时代淘汰?比尔盖茨预言下一个主角已登场随着信息时代的发展,电子设备已然成为人们日常必不可少的工具,比如电脑智能手机家用电器等。尤其是智能手机,它在我们的日常工作生活娱乐社交等方面扮演了一个重要的角色。可以说,如果没有智
郑重看股银行股会不会是资金抱团的下一个目标?银行股极有可能成为资金抱团的下一个目标。A股共有38家上市银行股,其中包括六大国有银行股。银行股市盈率是A股各大板块中最低的,其中有28家银行股市盈率低于10,有14家银行股市盈率当胎儿缺氧,往往有哪些临床表现?在孕期的过程中,如果哪一项事件让孕妈特别焦虑的话,可能就是胎儿缺氧,因为缺氧有短暂性的缺氧,还有长久性的缺氧,有些短暂性是非常的短,孕妈在孕期的过程中学会数胎动,记录胎动的次数非常为什么美国香港等地区允许在当地出生的婴儿有该地户口?国籍是一个非常重要的法律概念。在国内,拥有一国的国籍意味着接受该国法律的管辖和约束在国际上,拥有某国国籍意味着该国的外交和领事保护问题。目前,国际法上比较普遍的国籍原则是出生地主义坐月子需要注意事项特别多,哺乳期妈妈产后水果怎么吃才对呢?冬季坐月子水果煮着吃更温和哺乳期吃水果的好处水果的营养丰富,味道鲜美,男女老幼,人人爱吃。有些人认为,水果是生冷的食物,哺乳期妈妈怕着凉,吃生冷的水果对身体没有好处。实践证明,哺乳足坛黑幕又被撕烂,前国足高雷雷称,每个环节都要钱打点中国足坛的腐败,不只圈内人清楚,连圈外人也明白,已经是烂透了!近日,前国脚高雷雷实名举报中国足球黑幕说,自己就是中国足球腐败环境的受害者,当年韩日世界杯选人时,他都已经被米卢选进了足协反腐首次波及裁判,裁判培训班如期举行,中纪委出手调查反腐一直以来,关于中国足球的反腐打假事件备受社会各界关注。自去年11月国足前主帅李铁首先被带走调查后,包括中国足协主席陈戌源秘书长刘奕以及近日落网的王小平等人也相继落马,整个中国足协重裁判被抓?傅明马宁都还能联系上30号集训!李璇公开嘲讽爆料律师当足协官员俱乐部官员球员教练早已一一落网,很多圈内人就做出了下一步该抓裁判的预言。而代理了李帅戴伟浚等多名球员欠薪案件的著名律师张冰在大晚上也曝出了猛料今晚,裁判开始被拷走,我今天足球反腐败再深入深水区,裁判和球员涉赌将会是下一步调查的重点根据张冰律师的消息,已经有裁判被带走了。早在前些天我就认为这肯定是必然,既然有球员参与了足球,那么裁判和足协的纪律委员会是逃不掉的。当然源头还是山东泰山的球员吴兴涵老婆的爆料,说赌中国队水球亚锦赛时隔11年再夺冠!获水球世界杯参赛资格3月28日,据人民日报体育报道,2023亚洲水球锦标赛暨世界杯亚洲资格赛,中国男子水球队在决赛中以11比8战胜伊朗队,夺得冠军,也获得了5月在德国柏林举行的2023世界杯洲际杯赛的余承东和雷军谁的能力强?把雷军跟余承东比简直就是拉低雷老板的档次。这么说吧,雷军是跟柳传志,任正非同一梯队的。商业上,他是一个世界500强CEO,小米集团创始人,卓越网创始人,金山软件董事长,顺为资本掌门个人家庭的固定电话还需要保留吗?一般情况下没必要保留,但如果家里有老人并没有手机,货不会用智能手机还是保留座机更方便。现在是网络时代,固定电话的作用确实不大了,但我自己家里的固定电话还一直保留着,也有想过去注销,