百度App起步性能优化实践篇
<span style="color: black;"><p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;"><strong style="color: blue;"><strong style="color: blue;"><span style="color: black;"><span style="color: black;">一</span><span style="color: black;">.</span><span style="color: black;">前</span><span style="color: black;">言</span></span></strong></strong></strong></p>
</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">起步</span>性能是百度App最核心指标之一。用户<span style="color: black;">期盼</span>应用能够<span style="color: black;">即时</span>响应并快速加载,<span style="color: black;">起步</span>时间过长的应用<span style="color: black;">不可</span>满足这个期望,并且可能会令用户失望,这种糟糕的体验可能会<span style="color: black;">引起</span>用户在应用商店针对您的应用给出很低的评分,<span style="color: black;">乃至</span>完全抛弃您的应用。<span style="color: black;">起步</span>性能的优化<span style="color: black;">作为</span>了体验优化中最<span style="color: black;">重要</span>的一环,百度App<span style="color: black;">这里</span>方向<span style="color: black;">连续</span>投入,不断优化,<span style="color: black;">提高</span>用户体验。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">起步</span>性能优化分为概述篇、<span style="color: black;">工具</span>篇、优化篇和防劣化篇,本篇<span style="color: black;">文案</span><span style="color: black;">重点</span>阐述性能优化<span style="color: black;">关联</span>内容,前期已<span style="color: black;">发布</span><span style="color: black;">文案</span><span style="color: black;">能够</span>参阅:</span></p><span style="color: black;">百度App 低端机优化-<span style="color: black;">起步</span>性能优化(概述篇)</span>:<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">https://mp.weixin.qq.com/s/aomafRByyponPBiI79OoHQ</span></p><span style="color: black;">百度App Android<span style="color: black;">起步</span>性能优化-<span style="color: black;">工具</span>篇</span>:<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">https://mp.weixin.qq.com/s/kyTjEQutXQ7oqzN0htTOiA</span></p><span style="color: black;">百度App性能优化<span style="color: black;">工具</span>篇-Thor原理及实践</span><span style="color: black;">:</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">https://mp.weixin.qq.com/s/kKRNpQ0UNP2m0_vOS6D8HA</span></p><span style="color: black;">
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;"><strong style="color: blue;"><strong style="color: blue;"><span style="color: black;">二. </span></strong></strong></strong><span style="color: black;"><strong style="color: blue;"><span style="color: black;">优化理论</span></strong></span></p>
</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">对<span style="color: black;">起步</span>性能优化的认知,决定了<span style="color: black;">起步</span>性能优化的方向与思路,<span style="color: black;">从而</span>会决定优化的效果。</span><span style="color: black;">较多<span style="color: black;">研发</span>者对<span style="color: black;">起步</span>过程的认知,<span style="color: black;">源自</span>于Google <span style="color: black;">研发</span>者文档中有段对<span style="color: black;">起步</span>过程的描述:</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="https://mmbiz.qpic.cn/mmbiz_png/Ce6bSqXkduz9Uk3ibMLwKAYc6yDtCb2gdoPnnhAj4gPynH4QxrvpJWqcQuet5SzqCtxMkZzSK3ewAf3ZV8ywoSQ/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;"></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">创建应用对象;</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">起步</span>主线程;</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">创建主 activity;</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">扩充视图;</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">布局屏幕;</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">执行初始绘制。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">一旦应用进程完成<span style="color: black;">第1</span>次绘制,系统进程就会换掉当前<span style="color: black;">表示</span>的后台窗口,替换为主 activity。此时,用户<span style="color: black;">能够</span><span style="color: black;">起始</span><span style="color: black;">运用</span>应用。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">上面<span style="color: black;">重点</span>介绍了应用在<span style="color: black;">起步</span>过程中的各个<span style="color: black;">周期</span>,但其实只是大致概括,其实<span style="color: black;">起步</span>方式会比较多,极有可能在<span style="color: black;">区别</span>的<span style="color: black;">起步</span>路径执行的<span style="color: black;">规律</span>有差异,<span style="color: black;">因此呢</span>全路径的认知在优化过程中起到了非常<span style="color: black;">要紧</span>的<span style="color: black;">功效</span>,如下图所示:</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="https://mmbiz.qpic.cn/mmbiz_png/Ce6bSqXkduz9Uk3ibMLwKAYc6yDtCb2gdR8XrAPBrr7pjNCkVtapx1mic4NBbNrvTsibl5tPic2U0V7icvdTK4NXnVg/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;"></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">在<span style="color: black;">起步</span>过程中,点击桌面图标是主流冷<span style="color: black;">起步</span>方式,而Push调起,浏览器调起等端外转化<span style="color: black;">亦</span>是比较<span style="color: black;">平常</span>的调起方式,<span style="color: black;">各样</span><span style="color: black;">起步</span>方式的<span style="color: black;">起步</span>过程基本可拆解为:进程创建、框架加载、首页渲染、预加载四个环节。而<span style="color: black;">起步</span>性能优化<span style="color: black;">重点</span>面对的不只是点击桌面图标这一种路径,<span style="color: black;">更加多</span>的<span style="color: black;">必须</span><span style="color: black;">起步</span>全路径的优化,达到体验的极致优化。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">起步</span>过程<span style="color: black;">亦</span><span style="color: black;">必须</span>结合系统层面来理解,<span style="color: black;">从而</span>挖掘优化点,探索优化的极限。<span style="color: black;">起步</span>过程是非常复杂的过程,<span style="color: black;">必须</span>较多系统级进程<span style="color: black;">协同</span><span style="color: black;">才可</span>完成页面的展现,供用户正常<span style="color: black;">运用</span>,下图展示的点击icon的<span style="color: black;">起步</span>过程:</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="https://mmbiz.qpic.cn/mmbiz_png/Ce6bSqXkduz9Uk3ibMLwKAYc6yDtCb2gdvU6jVMgSYaFzbAibhr9YFFLXFupjqQtn4iaVtysKhEUUwS5tibrztbxjQ/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;"></p><span style="color: black;"><span style="color: black;">起步</span>过程大概可概括为:</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">Launcher<span style="color: black;">通告</span>AMS<span style="color: black;">起步</span>APP的主Activity;</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">ActivityManagerService(以下简<span style="color: black;">叫作</span>AMS)记录要<span style="color: black;">起步</span>的Activity信息,并且<span style="color: black;">通告</span>Launcher进入pause状态;</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">Launcher进入pause状态后,<span style="color: black;">通告</span>AMS<span style="color: black;">已然</span>paused了,<span style="color: black;">起始</span><span style="color: black;">起步</span>App;</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">App未开启过,AMS<span style="color: black;">起步</span>新的进程,并且在新进程中创建ActivityThread对象,执行其中的main函数<span style="color: black;">办法</span>;</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">App主线程<span style="color: black;">起步</span>完毕后<span style="color: black;">通告</span>AMS,并传入applicationThread以便通讯;</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">AMS<span style="color: black;">通告</span>App绑定Application并<span style="color: black;">起步</span>MainActivity;</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">起步</span>MainActivitiy,并且创建和<span style="color: black;">相关</span>Context,最后调用onCreate<span style="color: black;">办法</span>,<span style="color: black;">最后</span>完成页面绘制和上屏;</span></p><span style="color: black;"><span style="color: black;">重点</span>进程的功能<span style="color: black;">重点</span>是:</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">Launcher进程:为手机桌面进程,负责接收用户的点击事件,并将事件<span style="color: black;">通告</span>到AMS</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">SystemServer进程:负责应用的<span style="color: black;">起步</span>流程调度、进程的创建和管理、窗口的创建和管理(StartingWindow 和 AppWindow) 等,比较核心的服务有AMS和WMS(WindowManagerService);</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">Zygote进程:<span style="color: black;">经过</span>fork创建应用程序进程,Zygote进程在初始化时就会会创建虚拟机,<span style="color: black;">同期</span>把<span style="color: black;">必须</span>的系统类库和资源文件加载到内存中。而Zygote在fork出子进程后,这个子进程<span style="color: black;">亦</span>会得到一个<span style="color: black;">已然</span>加载好<span style="color: black;">基本</span>资源的虚拟机,从而加速应用进程的<span style="color: black;">起步</span>;</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">SurfaceFlinger进程:<span style="color: black;">重点</span>和应用的渲染<span style="color: black;">关联</span>,如Vsync信号处理、窗口的合成处理、帧缓冲区管理等。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">有了全局的认知和视野后,<span style="color: black;">咱们</span>就<span style="color: black;">能够</span>站在更高的<span style="color: black;">方向</span>,更加深入的思考与分析性能瓶颈,如手机负载<span style="color: black;">恰当</span>性、系统资源<span style="color: black;">运用</span>等等,更加全面的<span style="color: black;">思虑</span><span style="color: black;">起步</span>性能的优化方式,达到对<span style="color: black;">起步</span>性能的极致优化。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;"><strong style="color: blue;"><strong style="color: blue;"><span style="color: black;"><span style="color: black;">三. </span><span style="color: black;">优</span><span style="color: black;">化落地</span></span></strong></strong></strong></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">百度App的<span style="color: black;">起步</span>性能的优化,大致分为三部分,常规优化、<span style="color: black;">基本</span>机制优化和底层技术优化三部分。</span></p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;"><span style="color: black;"><strong style="color: blue;">丨</strong></span><span style="color: black;"><span style="color: black;"><span style="color: black;">3</span><span style="color: black;">.</span><span style="color: black;">1</span><span style="color: black;"> 常规优化</span></span></span></h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">倘若</span>是业务发展初期,业务的快速迭代较快,此时的优化会相对简单,极有可能会<span style="color: black;">显现</span><span style="color: black;">短期</span>内,<span style="color: black;">起步</span>速度<span style="color: black;">提高</span>秒级别的优化效果。<span style="color: black;">起步</span>性能的优化,<span style="color: black;">亦</span>是基于对冷<span style="color: black;">起步</span>的理解以及<span style="color: black;">起步</span>任务的梳理,达到快速优化的<span style="color: black;">目的</span>。可<span style="color: black;">经过</span>性能<span style="color: black;">工具</span>,如前文提过的Trace<span style="color: black;">工具</span>、Thor Hook<span style="color: black;">工具</span>,<span style="color: black;">发掘</span>耗时较为<span style="color: black;">明显</span>问题,<span style="color: black;">评定</span><span style="color: black;">是不是</span>可<span style="color: black;">经过</span>延迟、异步、删除等方式优化,依据投入产出<span style="color: black;">状况</span><span style="color: black;">评定</span>工作优先级,达到快速优化<span style="color: black;">起步</span>性能的目的。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="https://mmbiz.qpic.cn/mmbiz_png/Ce6bSqXkduz9Uk3ibMLwKAYc6yDtCb2gdh8V7fCCTdDC1LDlR0jw99AqWwXWjfPtpjHtHiardfJW21QR9gaKuGew/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;"></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">随着<span style="color: black;">起步</span>场景承载业务逐步庞大,手百<span style="color: black;">逐步</span>成长为承载业务最多,体量巨大的航母级移动端应用,庞大业务的预加载不可能完全去除<span style="color: black;">或</span><span style="color: black;">经过</span>异步来<span style="color: black;">处理</span>,此部分是<span style="color: black;">起步</span>性能优化中面临的<span style="color: black;">很强</span><span style="color: black;">困难</span>,<span style="color: black;">必须</span>有机制批量<span style="color: black;">处理</span>业务预加载问题,<span style="color: black;">因此呢</span><span style="color: black;">基本</span>机制中的调度机制<span style="color: black;">逐步</span>衍生出来,处理<span style="color: black;">起步</span>过程<span style="color: black;">区别</span>业务的预加载需求。</span></p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;"><span style="color: black;"><strong style="color: blue;">丨</strong></span><span style="color: black;"><span style="color: black;"><span style="color: black;">3</span><span style="color: black;">.2</span><span style="color: black;"> <span style="color: black;">基本</span>机制优化</span></span></span></h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">基本</span>机制优化<span style="color: black;">重点</span>分为调度机制优化、<span style="color: black;">基本</span>组件性能优化。</span></p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;"><span style="color: black;"><strong style="color: blue;">丨</strong></span><strong style="color: blue;">3.2.1 任务调度优化</strong></h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">业务多,预加载任务的执行诉求各有<span style="color: black;">区别</span>,平衡<span style="color: black;">起步</span>性能和业务预加载,百度App需建设任务调度框架,业务方<span style="color: black;">经过</span>接入可快速优化性能问题。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="https://mmbiz.qpic.cn/mmbiz_png/Ce6bSqXkduz9Uk3ibMLwKAYc6yDtCb2gdbEgjWGPnWib5Hn2EG9foLxicBtuWiaRPnBo2HibiaIImN7vybzLFUFFgCSg/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;"></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">任务调度整体建设<span style="color: black;">状况</span>如下,<span style="color: black;">日前</span>还处在快速迭代中:</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="https://mmbiz.qpic.cn/mmbiz_png/Ce6bSqXkduz9Uk3ibMLwKAYc6yDtCb2gd49axSKgt2IpIkCeicGJZkiatjf6M09FCvSAWr8D0vWDXZuWRXyrlxlOw/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;"></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">智能调度<span style="color: black;">能够</span><span style="color: black;">按照</span>任务输入和信息输入,做出<span style="color: black;">区别</span>的调度反应,如:</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">个性化调度策略:识别出业务预加载任务ID和用户<span style="color: black;">行径</span>习惯相匹配,则会将任务提前做初始化,任务优先级会做<span style="color: black;">提高</span>,与此<span style="color: black;">同期</span>,在用户进入业务对应页面时,非业务<span style="color: black;">关联</span>任务需做避让;</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">分级体验策略:识别出在指定的机型配置中有对应的调度策略,则会执行对应的调度能力,如立即调度、延迟调度、不调度等,<span style="color: black;">重点</span>用于体验降级;</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">精细化调度策略:在<span style="color: black;">区别</span>的场景精细化调度业务预加载任务,如在闪屏场景,会识别闪屏<span style="color: black;">关联</span>业务信息并做预加载,在端外调起场景,会识别落地页所属业务信息并做对应预加载;</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">分优先级延迟调度:有<span style="color: black;">很强</span>量的任务初始化会依赖于延迟调度,需<span style="color: black;">保证</span>有序<span style="color: black;">掌控</span>业务初始化,<span style="color: black;">因此呢</span>在延迟调度<span style="color: black;">基本</span>上添加优先级概念,<span style="color: black;">能够</span>在延迟调度中<span style="color: black;">亦</span>分优先级调度,让更高优先级任务<span style="color: black;">能够</span>更快的执行;</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">首页UI并行渲染调度:<span style="color: black;">重点</span>服务于冷<span style="color: black;">起步</span><span style="color: black;">周期</span><span style="color: black;">商场</span>闪屏业务,<span style="color: black;">商场</span>闪屏<span style="color: black;">是不是</span><span style="color: black;">必须</span>展现、展现哪个物料均是冷<span style="color: black;">起步</span><span style="color: black;">周期</span>的实时网络请求决定的,需在冷<span style="color: black;">起步</span><span style="color: black;">周期</span><span style="color: black;">尽可能</span><span style="color: black;">加强</span><span style="color: black;">商场</span>网络请求的可用时间,<span style="color: black;">从而</span><span style="color: black;">加强</span>网络请求成功率,百度App<span style="color: black;">日前</span><span style="color: black;">能够</span>实现,首页<span style="color: black;">能够</span>先初始化,但不做上屏,待首页渲染业务提交的时候再<span style="color: black;">检测</span><span style="color: black;">商场</span>闪屏<span style="color: black;">是不是</span>展现,做到了<span style="color: black;">供给</span>给<span style="color: black;">商场</span>网络请求<span style="color: black;">更加多</span>可用时间的<span style="color: black;">同期</span>不阻塞首页初始化,<span style="color: black;">经过</span>此项技术大幅<span style="color: black;">提高</span><span style="color: black;">商场</span>网络请求的成功率,带来了<span style="color: black;">商场</span>收入的<span style="color: black;">提高</span>。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">因为</span>调度器框架中<span style="color: black;">触及</span>细节非常多,在<span style="color: black;">这儿</span>只简单介绍其中一种调度器的设计:分级体验调度器。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="https://mmbiz.qpic.cn/mmbiz_png/Ce6bSqXkduz9Uk3ibMLwKAYc6yDtCb2gdp4I369XnHuCaCvuIYC4wyzthpksWhtCZLFgZgteKicS9fqibfUvcOrQQ/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;"></p><span style="color: black;"><span style="color: black;">重点</span>分为3个模块,机型评分、分级配置和分级调度机制,达到<span style="color: black;">区别</span>配置的手机上的最优体验。</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">机型评分:</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">经过</span>设备信息计算评分信息,<span style="color: black;">叫作</span>为静态评分;</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">经过</span>性能指标计算评分信息,<span style="color: black;">叫作</span>为动态评分;</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">依据模型训练评分信息,得出<span style="color: black;">最后</span>机型评分;</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">分级配置:</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">云端配置表:<span style="color: black;">供给</span>各业务级别按设备评分<span style="color: black;">要求</span>下的分级配置表,该表支持动态更新,增量更新,更新后端上<span style="color: black;">即时</span>生效。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">本地预置表:本地会预置一份配置表,供首次安装时<span style="color: black;">运用</span>;</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">依据机型评分信息和分级配置信息得出<span style="color: black;">掌控</span>策略;</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">分级调度:</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">业务方<span style="color: black;">按照</span>机型评分<span style="color: black;">掌控</span><span style="color: black;">区别</span>的业务<span style="color: black;">规律</span>,达到高端机<span style="color: black;">所有</span>功能最优体验,中端机部分功能良好体验,低端机核心功能流畅体验,如首页点赞动画在高端机上<span style="color: black;">选取</span>开启策略,中端机上<span style="color: black;">选取</span>延迟加载策略,低端机上<span style="color: black;">选取</span>关闭状态;</span></p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;"><span style="color: black;"><strong style="color: blue;">丨</strong></span><strong style="color: blue;">3.2.2 KV存储优化</strong></h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">SharedPreferences是Android平台轻量级的存储类,用来<span style="color: black;">保留</span>应用程序的配置信息,其本质是以“键-值”对的方式<span style="color: black;">保留</span>数据的xml文件,其文件<span style="color: black;">保留</span>在/data/data/p<span style="color: black;">公斤</span>/shared_prefs目录下,优点是以键值对的方式进行存储,<span style="color: black;">运用</span>方便,易于理解;但SharedPreferences的缺点很<span style="color: black;">显著</span>,读写性能慢,IO读写<span style="color: black;">运用</span>xml数据格式,全量更新效率低;多进程支持差,存储数据易丢失;创建线程多,<span style="color: black;">引起</span>性能差。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;"><span style="color: black;">读取性能差</span></strong></p><span style="color: black;">每加载一个SP文件均会创建子线程,源码如下:</span><span style="color: black;"><span style="color: black;">private</span> <span style="color: black;">final</span>Object mLock =<span style="color: black;">new</span> Object();</span><span style="color: black;"><span style="color: black;">private</span> <span style="color: black;">boolean</span> mLoaded = <span style="color: black;">false</span>;</span><span style="color: black;"><span style="color: black;"><span style="color: black;">private</span> <span style="color: black;">void</span> <span style="color: black;">startLoadFromDisk</span><span style="color: black;">()</span> </span>{</span><span style="color: black;"> <span style="color: black;">synchronized</span> (mLock) {</span><span style="color: black;"> mLoaded = <span style="color: black;">false</span>;</span><span style="color: black;"> }</span><span style="color: black;"> <span style="color: black;">new</span> Thread(<span style="color: black;">"SharedPreferencesImpl-load"</span>) {</span><span style="color: black;"> <span style="color: black;"><span style="color: black;">public</span> <span style="color: black;">void</span> <span style="color: black;">run</span><span style="color: black;">()</span> </span>{</span><span style="color: black;"> loadFromDisk();</span><span style="color: black;"> }</span><span style="color: black;"> }.start();</span><span style="color: black;">}</span><span style="color: black;"><span style="color: black;">然则</span>在获取key-value时<span style="color: black;">倘若</span><span style="color: black;">无</span>加载完成,则会wait等待SP文件加载完成:</span>
<div style="color: black; text-align: left; margin-bottom: 10px;"><span style="color: black;"><span style="color: black;">public</span> <span style="color: black;">String</span> getString(<span style="color: black;">String</span> key, <span style="color: black;">@Nullable</span> <span style="color: black;">String</span>defValue) {</span><span style="color: black;"> synchronized (mLock) {</span><span style="color: black;"> awaitLoadedLocked();</span><span style="color: black;"> <span style="color: black;">String</span> v = (<span style="color: black;">String</span>)mMap.get(key);</span><span style="color: black;"> <span style="color: black;">return</span> v != <span style="color: black;">null</span> ? v : defValue;</span><span style="color: black;"> }</span><span style="color: black;">}</span></div>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><strong style="color: blue;">写入性能差</strong></span></p><span style="color: black;">SP采用XML格式,每次写入是全量更新,效率低,写入<span style="color: black;">供给</span>两种方式:</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">commit:阻塞当前线程方式,修改提交到内存后,等待IO完成,<span style="color: black;">倘若</span>主线程<span style="color: black;">运用</span>commit方式,极有可能<span style="color: black;">显现</span>卡顿;</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">apply:不阻塞当前线程,但<span style="color: black;">亦</span>有<span style="color: black;">隐匿</span>的坑,可能会<span style="color: black;">引起</span>主线程的卡顿问题,<span style="color: black;">重点</span>原<span style="color: black;">由于</span>apply方式将写入Runnable加入到QueueWork中,而在Android 四大组件生命周期轮转时,会<span style="color: black;">检测</span>QueueWork<span style="color: black;">是不是</span>完成,<span style="color: black;">倘若</span><span style="color: black;">无</span>完成则会wait,代码如:</span></p>
<div style="color: black; text-align: left; margin-bottom: 10px;"><span style="color: black;"> <span style="color: black;"><span style="color: black;">public</span> <span style="color: black;">void</span> <span style="color: black;">handlePauseActivity</span><span style="color: black;">(IBinder token, <span style="color: black;">boolean</span> finished, <span style="color: black;">boolean</span> userLeaving,</span></span></span><span style="color: black;"><span style="color: black;"> <span style="color: black;">int</span>configChanges, PendingTransactionActions pendingActions, String reason)</span> {</span><span style="color: black;"> ......</span><span style="color: black;"> <span style="color: black;">// <span style="color: black;">保证</span>写任务都<span style="color: black;">已然</span>完成</span></span><span style="color: black;"> QueuedWork.waitToFinish();</span><span style="color: black;"> ......</span><span style="color: black;"> }</span><span style="color: black;">}</span></div><span style="color: black;"><span style="color: black;">因此呢</span>,在ANR/卡顿监控中能看到非常多的SharedPreferences堆栈,看堆栈是系统级堆栈,但其实是SP apply方式引入的问题,堆栈如:</span><span style="color: black;">java.lang.Object.wait(Native Method) </span><span style="color: black;"><span style="color: black;">java.lang.Thread.parkFor$(Thread.java: ) </span></span><span style="color: black;"><span style="color: black;">sun.misc.Unsafe.park(Unsafe.java: )</span></span><span style="color: black;"><span style="color: black;">java.util.concurrent.locks.LockSupport.park(LockSupport.java: )</span></span><span style="color: black;"><span style="color: black;">java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java: ) </span></span><span style="color: black;"><span style="color: black;">java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java: )</span></span><span style="color: black;"><span style="color: black;">java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java: )</span></span><span style="color: black;"><span style="color: black;">java.util.concurrent.CountDownLatch.await(CountDownLatch.java: ) </span></span><span style="color: black;"><span style="color: black;">android.app.SharedPreferencesImpl$EditorImpl$1.run(SharedPreferencesImpl.java: )</span></span><span style="color: black;"><span style="color: black;">android.app.QueuedWork.waitToFinish(QueuedWork.java: ) </span></span><span style="color: black;"><span style="color: black;">android.app.ActivityThread.handleServiceArgs(ActivityThread.java: )</span></span><span style="color: black;">android.app.ActivityThread. - wrap21(ActivityThread.java) </span><span style="color: black;"><span style="color: black;">android.app.ActivityThread$H.handleMessage(ActivityThread.java: )</span></span><span style="color: black;"><span style="color: black;">android.os.Handler.dispatchMessage(Handler.java: ) </span></span><span style="color: black;"><span style="color: black;">ndroid.os.Looper.loop(Looper.java: ) </span></span><span style="color: black;"><span style="color: black;">ndroid.app.ActivityThread.main(ActivityThread.java: )</span></span><span style="color: black;">java.lang.reflect.Method.invoke(Native Method) </span><span style="color: black;"><span style="color: black;">com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java: ) </span></span><span style="color: black;"><span style="color: black;">com.android.internal.os.ZygoteInit.main(ZygoteInit.java: )</span></span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><strong style="color: blue;">多进程支持差</strong></span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">当<span style="color: black;">运用</span>MODE_MULTI_PROCESS这个字段时,其实并不<span style="color: black;">靠谱</span>,<span style="color: black;">由于</span>Android内部并<span style="color: black;">无</span>合适的机制去防止多个进程所<span style="color: black;">导致</span>的冲突,应用<span style="color: black;">不该</span>该<span style="color: black;">运用</span>它,<span style="color: black;">举荐</span><span style="color: black;">运用</span>ContentProvider。上面这段介绍<span style="color: black;">咱们</span>得知:多个进程<span style="color: black;">拜访</span>{MODE_MULTI_PROCESS}标识的SharedPreferences时,会<span style="color: black;">导致</span>冲突,举个例子<span style="color: black;">便是</span>,在A进程,明明set了一个key进去,跳到B进程去取,却提示null的错误。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="https://mmbiz.qpic.cn/mmbiz_png/Ce6bSqXkduz9Uk3ibMLwKAYc6yDtCb2gdZDaicTONR1MBVVE85KMts5eZMba2CiaObGgzrBFKcXt8pm4evsLJz0lw/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;"></p><span style="color: black;"><strong style="color: blue;">3.2.2.1 优化<span style="color: black;">方法</span>设计</strong></span><span style="color: black;"><span style="color: black;">日前</span>各大厂商<span style="color: black;">亦</span>对SP做了<span style="color: black;">必定</span>优化,有保守优化,在SP当前机制<span style="color: black;">基本</span>上做优化,<span style="color: black;">重点</span>是解决写入<span style="color: black;">引起</span>的ANR问题;<span style="color: black;">亦</span>有颠覆性优化,比较有<span style="color: black;">表率</span>性的为MMKV和Data Store,但经<span style="color: black;">评定</span>后,可能均有<span style="color: black;">必定</span>问题,<span style="color: black;">因此呢</span>在百度App的优化中,<span style="color: black;">亦</span>是学习借鉴业界主流的处理方式,<span style="color: black;">最后</span>采用两种优化并存的方式:</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">供给</span>颠覆性优化组件:UniKV,彻底<span style="color: black;">处理</span>原生SP一系列问题,核心场景极致体验,业务方主动接入;</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">在系统SP机制上做优化,<span style="color: black;">处理</span>写入时ANR等痛点问题,<span style="color: black;">重点</span>服务于未接入UniKV的SP文件;</span></p><span style="color: black;"><strong style="color: blue;"><span style="color: black;">3.2.2.1.1 UniKV设计</span></strong></span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><strong style="color: blue;"><span style="color: black;">层级设计</span></strong></span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="https://mmbiz.qpic.cn/mmbiz_png/Ce6bSqXkduz9Uk3ibMLwKAYc6yDtCb2gdhc9VdhkHYhMOPlvYPnJebMO3znCEuwia0oeRPq2Qic7tyMIE6nTU6frQ/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;"></p><span style="color: black;">1: 业务<span style="color: black;">运用</span>时直接依赖UniKV,UniKV继承SharedPreferences,对齐原生SP接口;</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">2: 工程中<span style="color: black;">包括</span>原生实现和UniKV实现,代码中直接依赖原生实现,编译打包时替换为UniKV实现,<span style="color: black;">保准</span>业务中台输出能力;</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><strong style="color: blue;"><span style="color: black;">文件存储格式设计</span></strong></span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">分位文件头、数据块。文件头40个字节,<span style="color: black;">重点</span>存储版本号、回写次数、<span style="color: black;">保存</span>字段、容灾数据长度、容灾CRC、<span style="color: black;">实质</span>数据长度、<span style="color: black;">实质</span>CRC。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="https://mmbiz.qpic.cn/mmbiz_png/Ce6bSqXkduz9Uk3ibMLwKAYc6yDtCb2gd5RC0v6ibnkP7eaWnS8o8A6icRFXDmDtYicqeUJz6nFEVmbW5Opd5o0IdA/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;"></p><span style="color: black;">1:以</span><span style="color: black;">4KB位单位分配空间,最小占用4KB空间,<span style="color: black;">经过</span>mmap映射文件,操作系统负责数据写入文件;</span><span style="color: black;">2:<span style="color: black;">经过</span>容灾数据长度和容灾CRC可做数据恢复;</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">3:<span style="color: black;">经过</span><span style="color: black;">保存</span>字段可做功能拓展,<span style="color: black;">例如</span><span style="color: black;">是不是</span>从SP迁移成功标识;</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="https://mmbiz.qpic.cn/mmbiz_png/Ce6bSqXkduz9Uk3ibMLwKAYc6yDtCb2gdiadb2wuEMCr864SibQI9GylBjicL4w5tm80tESZrUhPuzO0eLmBnDyTMA/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;"></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">数据块中存储<span style="color: black;">重点</span>数据体,以append形式写入,必要时再做数据整理</span></p><span style="color: black;">1:支持类型存储,对齐SP原生getAll接口;</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">2:支持类型有:BOOL、INT、FLOAT、DOUBLE、SHORT、LONG、STRING、STRING_ARRAY、BYTE_ARRAY9种类型,相比于原生SP实现支持类型<span style="color: black;">更加多</span>;</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><strong style="color: blue;">数据迁移</strong></span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">数据迁移过程<span style="color: black;">必须</span>先读取SP内容,再写入KV文件,耗时会较久,写入完成后KV文件才可用,这在线上会有隐患,<span style="color: black;">必须</span><span style="color: black;">处理</span>。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="https://mmbiz.qpic.cn/mmbiz_png/Ce6bSqXkduz9Uk3ibMLwKAYc6yDtCb2gdpiavZcWhvuKU2Njw6Ep5JrpUcWcQXNibNicqd6TM1rJt4zqZmnyUpLUrg/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;"></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">UniKV中数据迁移采用不影响业务方式,<span style="color: black;">倘若</span>迁移完成,则会直接<span style="color: black;">运用</span>KV文件,<span style="color: black;">倘若</span>未迁移完成,则继续<span style="color: black;">运用</span>SP文件,并将数据迁移Runnable提交至线程池。为避免数据迁移<span style="color: black;">时期</span>SP文件<span style="color: black;">显现</span>改动<span style="color: black;">引起</span>数据丢失,注册SP文件更改的数据监听。迁移完成标记位由<span style="color: black;">保存</span>字段来存储,<span style="color: black;">常常</span>数据迁移时<span style="color: black;">必须</span>标记位来<span style="color: black;">保留</span><span style="color: black;">是不是</span>迁移完成的Flag,<span style="color: black;">必须</span>引入其他文件来<span style="color: black;">保留</span>,此处UniKV里的<span style="color: black;">保存</span>字段很好的<span style="color: black;">处理</span>了此问题。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><strong style="color: blue;"><span style="color: black;">多进程实现</span></strong></span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">采用mmap机制 + 自定义文件锁实现进程间数据同步,mmap文件至<span style="color: black;">每一个</span>进程的内存空间,自定义文件锁<span style="color: black;">重点</span>实现的递归锁和锁的升降级,多进程读时共享锁,多进程写时排他锁,原生文件锁不支持递归锁,升降级容易死锁或锁会被完全释放,<span style="color: black;">因此呢</span>自定义文件锁实现进程间数据同步。关于多进程这块实现,<span style="color: black;">重点</span>学习了MMKV的多进程实现<span style="color: black;">规律</span>,感兴趣的<span style="color: black;">能够</span>参阅:</span><span style="color: black;">https://github.com/Tencent/MMKV/wiki/android_ipc</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><strong style="color: blue;">实现效果</strong></span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">彻底<span style="color: black;">处理</span>原生SP的性能问题,读写性能<span style="color: black;">明显</span><span style="color: black;">加强</span>,支持多进程读写,减少线程创建,整体性能指标和业务指标均<span style="color: black;">显现</span>了<span style="color: black;">显著</span>优化。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="data:image/svg+xml,%3C%3Fxml version=1.0 encoding=UTF-8%3F%3E%3Csvg width=1px height=1px viewBox=0 0 1 1 version=1.1 xmlns=http://www.w3.org/2000/svg xmlns:xlink=http://www.w3.org/1999/xlink%3E%3Ctitle%3E%3C/title%3E%3Cg stroke=none stroke-width=1 fill=none fill-rule=evenodd fill-opacity=0%3E%3Cg transform=translate(-249.000000, -126.000000) fill=%23FFFFFF%3E%3Crect x=249 y=126 width=1 height=1%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E" style="width: 50%; margin-bottom: 20px;"></p><span style="color: black;"><strong style="color: blue;"><span style="color: black;">3.2.2.1.2 系统SP机制优化</span></strong></span><span style="color: black;">有些SP是在插件、第三方SDK中<span style="color: black;">运用</span>的,<span style="color: black;">因此呢</span><span style="color: black;">没</span>法<span style="color: black;">运用</span>UniKV统一优化,需<span style="color: black;">供给</span>一种优化原生SP机制的<span style="color: black;">方法</span>。</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">优化<span style="color: black;">方法</span>:</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><strong style="color: blue;">Android版本</strong></span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><strong style="color: blue;">ANR类型</strong></span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><strong style="color: blue;">ANR<span style="color: black;">原由</span></strong></span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><strong style="color: blue;">性能平台ANR数据</strong></span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><strong style="color: blue;">优化思路</strong></span></p><span style="color: black;">Android<8.0</span><span style="color: black;">writenToDiskLatch.wait</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">writenToDiskLatch.wait等待子线程写入完成</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">Top 3,ANR占比:4.7%</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">动态代理QueueWork的<span style="color: black;">sPendingWorkFinishers,使poll返回null</span></span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">Android>=</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">8.0</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">writenToDiskLatch.wait</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">writenToDiskLatch.wait等待子线程写入完成</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">Top 15,ANR占比:0.5%</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">动态代理QueueWork的<span style="color: black;">sFinishers,使poll返回null</span></span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">processPendingWork</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">main线程已<span style="color: black;">得到</span>sProcessLock锁,在main正在执行写磁盘任务writeToFile,但耗时过大</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">Top 11,ANR占比:0.8%</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">代理sWork的clone函数都返回空队列;<span style="color: black;">经过</span>反射获取QueuedWork的mHandler的Looper对象,创建一个新的Hander,并将sWork中的任务提交到这个Handler去执行,从而实现了<span style="color: black;">没</span>阻塞运行</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">processPendingWork</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">main线程等在了获取 sProcessLock锁,子线程<span style="color: black;">得到</span>了sProcessLock锁在执行写磁盘任务,main等待时间过长</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">Top 7,ANR占比:1.8%</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">代理sWork的clone函数都返回空队列;<span style="color: black;">经过</span>反射获取QueuedWork的mHandler的Looper对象,创建一个新的Hander,并将sWork中的任务提交到这个Handler去执行,从而实现了<span style="color: black;">没</span>阻塞运行</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">日前</span>百度App 在Android 12上暂未优化,<span style="color: black;">重点</span><span style="color: black;">原由</span>是Android 12实现方式有变化,代理方式相对<span style="color: black;">繁杂</span>,且开销<span style="color: black;">很强</span>,而SP<span style="color: black;">导致</span>的ANR问题较少,<span style="color: black;">因此呢</span>暂未上线优化。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">优化效果:</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">此<span style="color: black;">方法</span>对全局均有优化,除了ANR指标有<span style="color: black;">明显</span>下降外,DAU和留存<span style="color: black;">亦</span><span style="color: black;">显现</span>正向。有<span style="color: black;">朋友</span>会担心优化后数据写入<span style="color: black;">是不是</span>会受影响,<span style="color: black;">咱们</span><span style="color: black;">经过</span>打点监控到SP写入<span style="color: black;">即时</span>性<span style="color: black;">无</span><span style="color: black;">显著</span>变化,而写入成功率出了正向,低端机<span style="color: black;">提高</span><span style="color: black;">显著</span>,说明SP优化减少ANR的<span style="color: black;">出现</span>,<span style="color: black;">更加多</span>任务被执行,写入成功率<span style="color: black;">提高</span>。</span></p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;"><span style="color: black;"><strong style="color: blue;">丨</strong></span><strong style="color: blue;"><span style="color: black;">3.2.3 锁优化</span></strong></h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">多线程性能调优是性能优化中不可避免的<span style="color: black;">专题</span>,为了实现线程同步,加入了同步锁机制(Synchronized同步锁、Lock同步锁等),同步锁的诞生虽然<span style="color: black;">保准</span>了操作的原子性、线程的安全性,<span style="color: black;">然则</span>(相比不加锁的<span style="color: black;">状况</span>下)造<span style="color: black;">成为了</span>程序性能下降。<span style="color: black;">因此</span>,<span style="color: black;">咱们</span><span style="color: black;">这儿</span>要做的一件事<span style="color: black;">便是</span>“锁优化”,即既要<span style="color: black;">保准</span>实现锁的功能(即<span style="color: black;">保准</span>多线程下操作安全)又要<span style="color: black;">加强</span>程序性能(即不要让程序<span style="color: black;">由于</span>安全而损失太大效率)。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">平常</span>的锁优化方式:</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="data:image/svg+xml,%3C%3Fxml version=1.0 encoding=UTF-8%3F%3E%3Csvg width=1px height=1px viewBox=0 0 1 1 version=1.1 xmlns=http://www.w3.org/2000/svg xmlns:xlink=http://www.w3.org/1999/xlink%3E%3Ctitle%3E%3C/title%3E%3Cg stroke=none stroke-width=1 fill=none fill-rule=evenodd fill-opacity=0%3E%3Cg transform=translate(-249.000000, -126.000000) fill=%23FFFFFF%3E%3Crect x=249 y=126 width=1 height=1%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E" style="width: 50%; margin-bottom: 20px;"></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">下面以一个优化项,介绍百度App在锁优化中的<span style="color: black;">实质</span>优化落地。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">在项目开展初期,通过Trace<span style="color: black;">工具</span>分析<span style="color: black;">发掘</span>有较多的“monitor contentation XXX”,此部分信息是Android ART虚拟机输出的锁<span style="color: black;">关联</span>信息,其中会<span style="color: black;">包含</span>持有锁的线程、<span style="color: black;">办法</span>、等锁线程、等锁<span style="color: black;">办法</span>。<span style="color: black;">详细</span>如下图所示:</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="data:image/svg+xml,%3C%3Fxml version=1.0 encoding=UTF-8%3F%3E%3Csvg width=1px height=1px viewBox=0 0 1 1 version=1.1 xmlns=http://www.w3.org/2000/svg xmlns:xlink=http://www.w3.org/1999/xlink%3E%3Ctitle%3E%3C/title%3E%3Cg stroke=none stroke-width=1 fill=none fill-rule=evenodd fill-opacity=0%3E%3Cg transform=translate(-249.000000, -126.000000) fill=%23FFFFFF%3E%3Crect x=249 y=126 width=1 height=1%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E" style="width: 50%; margin-bottom: 20px;"></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">经分析,<span style="color: black;">重点</span>是<span style="color: black;">基本</span>组件的AB在初始化时<span style="color: black;">因为</span>synchronized<span style="color: black;">重要</span>字不正确<span style="color: black;">运用</span><span style="color: black;">引起</span>,需对AB做性能优化,必要时做架构升级。而经过分析,AB<span style="color: black;">基本</span>组件在多线程、文件IO性能均存在性能问题,<span style="color: black;">因此呢</span>对AB<span style="color: black;">基本</span>组件做了重构升级,彻底<span style="color: black;">处理</span>性能问题。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="data:image/svg+xml,%3C%3Fxml version=1.0 encoding=UTF-8%3F%3E%3Csvg width=1px height=1px viewBox=0 0 1 1 version=1.1 xmlns=http://www.w3.org/2000/svg xmlns:xlink=http://www.w3.org/1999/xlink%3E%3Ctitle%3E%3C/title%3E%3Cg stroke=none stroke-width=1 fill=none fill-rule=evenodd fill-opacity=0%3E%3Cg transform=translate(-249.000000, -126.000000) fill=%23FFFFFF%3E%3Crect x=249 y=126 width=1 height=1%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E" style="width: 50%; margin-bottom: 20px;"></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">经过</span>优化后,读写采用</span><span style="color: black;"><span style="color: black;">没</span>锁</span><span style="color: black;">实现,彻底<span style="color: black;">处理</span>业务<span style="color: black;">运用</span>ABTest组件锁同步问题;兼容新老AB数据,缓存实验开关和实验sid数据,并采用JSON/PB数据格式存储,</span><span style="color: black;">首次读取性能118ms,优化95%</span><span style="color: black;">(小米5<span style="color: black;">设备</span>)。</span></p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;"><span style="color: black;"><strong style="color: blue;">丨</strong></span><strong style="color: blue;">3.2.4 其他<span style="color: black;">基本</span>机制优化</strong></h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">在百度App的<span style="color: black;">起步</span>性能优化中,开展过较多的<span style="color: black;">基本</span>机制<span style="color: black;">关联</span>优化,如:线程优化、IO优化、SO优化、主线程优先级优化、ContentProvider优化、类/<span style="color: black;">照片</span>预加载优化、<span style="color: black;">照片</span>预上传GPU优化等。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><strong style="color: blue;">线程优化</strong></span></p><span style="color: black;"><span style="color: black;">经过</span>Hook能力编写插件,<span style="color: black;">发掘</span>线程<span style="color: black;">运用</span>不规范问题,制定线程<span style="color: black;">运用</span>规范,如:</span><span style="color: black;">1: 业务禁止私自设置线程优先级;</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">2: <span style="color: black;">供给</span>统一的线程池,避免各业务各一个线程池;</span></p><span style="color: black;">3:优先<span style="color: black;">选取</span>线程池/任务调度器调度,业务禁止单独创建线程/线程池;</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">4: 线程池需避免线程频繁创建,参数标准化。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><strong style="color: blue;">IO优化</strong></span></p><span style="color: black;"><span style="color: black;">经过</span>Hook能力编写插件,<span style="color: black;">发掘</span>不<span style="color: black;">恰当</span>IO问题,<span style="color: black;">重点</span><span style="color: black;">包含</span>:</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">主线程读写时间超过100ms,主线程读写时间过长会<span style="color: black;">引起</span>主线程长耗时问题,严重时可能会<span style="color: black;">引起</span>ANR问题;</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">读写buffer过小问题,<span style="color: black;">倘若</span>buffer太小,会<span style="color: black;">引起</span><span style="color: black;">太多</span>次系统调用和内存拷贝,read/wirte次数<span style="color: black;">太多</span>,从而影响性能。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><strong style="color: blue;">SO优化</strong></span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">经过</span>Hook能力编写插件,<span style="color: black;">发掘</span>So加载问题,优化不必要的SO加载过程,<span style="color: black;">针对</span>必要的加载,尝试<span style="color: black;">经过</span>异步线程提前策略<span style="color: black;">处理</span>,达到优化性能的目的。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><strong style="color: blue;">Binder优化</strong></span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">经过</span>Hook能力编写插件,<span style="color: black;">发掘</span>Binder通信<span style="color: black;">关联</span>问题,优化不必要Binder通信,必要时可<span style="color: black;">经过</span>内存缓存、文件持久化等方式,达到优化性能的目的。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><strong style="color: blue;">主线程优先级</strong></span></p><span style="color: black;">主线程的优先级决定了系统为主线程分配的资源,<span style="color: black;">倘若</span>线程优先级有问题,被改<span style="color: black;">成为了</span>低优先级,极有可能<span style="color: black;">显现</span>得不到CPU时间片<span style="color: black;">引起</span>运行慢的问题。在主线程优先级的问题排查中,最有<span style="color: black;">表率</span>性的是业务在为<span style="color: black;">关联</span>子线程设置优先级时误设置了优先级,出问题方式:</span>
<div style="color: black; text-align: left; margin-bottom: 10px;"><span style="color: black;">Thread t = <span style="color: black;">new</span> Thread();</span><span style="color: black;">t.start();</span><span style="color: black;">t.setPriority(<span style="color: black;">3</span>);</span></div>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><a style="color: black;"><span style="color: black;">Android的离</span></a>奇陷阱—设置线程优先级<span style="color: black;">引起</span>的<span style="color: black;">微X</span>卡顿惨案<span style="color: black;">:</span><span style="color: black;">https://mp.weixin.qq.com/s/oLz_F7zhUN6-b-KaI8CMRw</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">在百度App排查优先级设置时,原生库<span style="color: black;">亦</span>有更改线程优先级<span style="color: black;">规律</span>,<span style="color: black;">亦</span>需主动修正,如facebook react库的部分<span style="color: black;">规律</span>:</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="data:image/svg+xml,%3C%3Fxml version=1.0 encoding=UTF-8%3F%3E%3Csvg width=1px height=1px viewBox=0 0 1 1 version=1.1 xmlns=http://www.w3.org/2000/svg xmlns:xlink=http://www.w3.org/1999/xlink%3E%3Ctitle%3E%3C/title%3E%3Cg stroke=none stroke-width=1 fill=none fill-rule=evenodd fill-opacity=0%3E%3Cg transform=translate(-249.000000, -126.000000) fill=%23FFFFFF%3E%3Crect x=249 y=126 width=1 height=1%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E" style="width: 50%; margin-bottom: 20px;"></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><strong style="color: blue;">ContentProvider/FileProvider优化</strong></span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">在Application.attachbaseContext和Application.onCreate之间,会执行installContentProviders<span style="color: black;">办法</span>,<span style="color: black;">这里</span><span style="color: black;">办法</span>中会执行AndroidManifest中声明的ContentProvider/FileProvider,<span style="color: black;">通常</span>耗时<span style="color: black;">很强</span>的为FileProvider,<span style="color: black;">重点</span><span style="color: black;">原由</span>是FileProvider初始化时有IO操作。<span style="color: black;">重点</span>优化为将ContentProvder/FileProvider移除,并<span style="color: black;">经过</span>android:process属性做<span style="color: black;">掌控</span>,<span style="color: black;">或</span><span style="color: black;">经过</span>懒加载方式,必要进程中初始化。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><strong style="color: blue;"><span style="color: black;">照片</span>prepareToDraw优化</strong></span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="data:image/svg+xml,%3C%3Fxml version=1.0 encoding=UTF-8%3F%3E%3Csvg width=1px height=1px viewBox=0 0 1 1 version=1.1 xmlns=http://www.w3.org/2000/svg xmlns:xlink=http://www.w3.org/1999/xlink%3E%3Ctitle%3E%3C/title%3E%3Cg stroke=none stroke-width=1 fill=none fill-rule=evenodd fill-opacity=0%3E%3Cg transform=translate(-249.000000, -126.000000) fill=%23FFFFFF%3E%3Crect x=249 y=126 width=1 height=1%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E" style="width: 50%; margin-bottom: 20px;"></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">在Trace<span style="color: black;">工具</span>有会看到RenderThread中执行syncFrameState时会upload XXX Texture<span style="color: black;">关联</span>耗时问题,<span style="color: black;">首要</span><span style="color: black;">检测</span>在trace里面<span style="color: black;">表示</span>的<span style="color: black;">照片</span>的宽和高,<span style="color: black;">保证</span><span style="color: black;">照片</span>的<span style="color: black;">体积</span>不比它<span style="color: black;">表示</span>出来的区域大太多。<span style="color: black;">亦</span><span style="color: black;">能够</span><span style="color: black;">经过</span>prepareToDraw<span style="color: black;">办法</span>提前触发Bitmap上传GPU操作,这种方式<span style="color: black;">能够</span>使Bitmap在RenderThread空闲的时候提前完成。理想<span style="color: black;">状况</span>下,<span style="color: black;">照片</span>加载库会<span style="color: black;">帮忙</span>你完成这些;<span style="color: black;">倘若</span>你想要自己掌控<span style="color: black;">照片</span>加载,<span style="color: black;">或</span><span style="color: black;">必须</span><span style="color: black;">保证</span>不在绘制的时候触发Bitmap上传,<span style="color: black;">能够</span>直接在代码里面调用 prepareToDraw。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">可能有的<span style="color: black;">朋友</span>比较疑惑,此优化<span style="color: black;">无</span>优化主线程,会对<span style="color: black;">起步</span>性能有优化吗?答案是<span style="color: black;">能够</span>优化主线程,在<span style="color: black;">起步</span>的前几帧,每一帧耗时均会比<span style="color: black;">很强</span>,而每一帧的任务在RenderThread中以DrawFrame Task运行,<span style="color: black;">倘若</span>上一帧的任务<span style="color: black;">无</span>完成,则会阻塞当前帧的绘制,主线程中<span style="color: black;">表现</span>出来的<span style="color: black;">便是</span>draw过程变慢,如nSyncAndDrawFrame执行时长过长。</span></p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;"><span style="color: black;"><strong style="color: blue;">丨</strong></span><span style="color: black;"><span style="color: black;"><span style="color: black;">2</span><span style="color: black;">.3</span><span style="color: black;"> 底层机制优化</span></span></span></h3>
<h2 style="color: black; text-align: left; margin-bottom: 10px;"><span style="color: black;"><span style="color: black;">重点</span><span style="color: black;">经过</span>探索底层的技术,来实现优化性能指标,<span style="color: black;">从而</span>撬动业务价值的<span style="color: black;">目的</span>,此方向<span style="color: black;">危害</span>性相对较高,成本<span style="color: black;">亦</span>会<span style="color: black;">很强</span>,需依据<span style="color: black;">详细</span>人力<span style="color: black;">状况</span>及优化效果做<span style="color: black;">最后</span>决策。</span></h2>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">百度App中<span style="color: black;">日前</span>已尝试过的有VerifyClass优化、CPU Booster优化、GC<span style="color: black;">关联</span>优化等,<span style="color: black;">日前</span>还在探索<span style="color: black;">有些</span>技术点,此部分优化基本为全局优化,会在后续的流畅度专题中为<span style="color: black;">大众</span>揭晓。</span></p>
<h1 style="color: black; text-align: left; margin-bottom: 10px;"><strong style="color: blue;"><span style="color: black;">小结</span></strong></h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">起步</span>性能优化是相对<span style="color: black;">繁杂</span>的技术方向,不仅有较多的业务会和<span style="color: black;">起步</span>性能有千丝万缕的联系,在<span style="color: black;">起步</span>过程中<span style="color: black;">亦</span>有非常多的系统<span style="color: black;">行径</span>值得关注与投入,<span style="color: black;">日前</span>百度App<span style="color: black;">起步</span>性能已<span style="color: black;">逐步</span>步入瓶颈期,<span style="color: black;">怎样</span>打破瓶颈并与业务紧密结合,是<span style="color: black;">起步</span>性能优化的挑战与机遇。<span style="color: black;">起步</span>性能的优化是<span style="color: black;">持续</span>学习、<span style="color: black;">持续</span>颠覆、<span style="color: black;">持续</span>进步的过程,中间可能会遇到非常多的挑战,<span style="color: black;">亦</span>会<span style="color: black;">显现</span>非常多的机遇,<span style="color: black;">因此呢</span>,<span style="color: black;">起步</span>性能优化永<span style="color: black;">没</span>止境,任重而道远。</span></p>
<h1 style="color: black; text-align: left; margin-bottom: 10px;"><strong style="color: blue;"><span style="color: black;">参考资料:</span></strong></h1><span style="color: black;">1、抖音<span style="color: black;">起步</span>优化</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">https://heapdump.cn/article/3624814</span></p><span style="color: black;">2、快手TTI 治理经验分享</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">https://zhuanlan.zhihu.com/p/422859543</span></p><span style="color: black;">3、浅析Android<span style="color: black;">起步</span>优化</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">https://juejin.cn/post/7183144743411384375</span></p><span style="color: black;">4、MMKV:</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">https://github.com/Tencent/MMKV/wiki/android_ipc</span></p>
“板凳”(第三个回帖的人) 大势所趋,用于讽刺一些制作目的就是为了跟风玩梗,博取眼球的作品。 感谢你的精彩评论,带给我新的思考角度。 楼主听话,多发外链好处多,快到碗里来!外链论坛 http://www.fok120.com/ 外链发布社区 http://www.fok120.com/ 回顾历史,我们感慨万千;放眼未来,我们信心百倍。
页:
[1]