今日头条 ANR 优化实践系列 - 告别 SharedPreference 等待

发表于 3年以前  | 总阅读数:459 次

简述

前面系列文章(详见文末)中介绍了安卓系统 ANR 设计原理以及我们在实际工作中对 ANR 进行监控得到的方案,基于常规的监控治理方案,ANR 问题得到了有效的抑制,但是有些系统组件的设计初衷与开发人员在实际使用过程中实际使用的背离,导致的冲突问题亟待解决,当前文章针对实际开发过程中滥用 sp 导致的 ANR 问题,如何从系统层面跳过 Google 设计缺陷,规避 ANR 问题。

Google 在设计之初为了方便开发者,实现了一套轻量级的数据持久化方案——SharedPreference(以下简称 sp),因为其简便的 API,方便的使用方式,得到开发者的青睐,对其依赖越来越重。在应用版本不断迭代的过程中发现 Google 说的轻量级的数据存储是有原因的,越是重量级的应用出现的 ANR 问题越严重。本文从源码层面分析在加载和写入过程中,导致 ANR 问题的原因以及相关的优化解决方案。

SP 导致 ANR 原因分析

经常会遇到两类关于 SharedPreference 问题,以下分别介绍导致这两类 ANR 问题的原因和优化方案。

问题一:sp 文件创建以后,会单独的使用一个线程来加载解析对应的 sp 文件。但是当 UI 线程尝试访问 sp 中内容时,如果 sp 文件还未被完全加载解析到内存,此时 UI 线程会被 block,直到 SP 文件被完全加载到内存中为止。具体 ANR 线程堆栈如下:

主要原因是 SP 文件未被加载或解析到内存中,此时无法直接使用 sp 提供的接口。sp 被创建的时候会同时启动一个线程加载对应的 sp 文件,执行 startLoadFromDisk();

在 startLoadFromDisk()时,标记 sp 不可使用状态,后期无论是尝试读数据或者写数据,读写线程都会被 block,直到 sp 文件被全部加载解析完毕。

线程在读或写时,都会走到 awaitLoadedLocked()逻辑,在上图的 mLoaded 为 false 即 sp 文件尚未加载解析到内存,此时读写线程会直接被 block 到 mLock 锁上,直到 loadFromDisk()方法执行完毕。

sp 文件完全加载解析到内存中,直接唤起所有在等待在当前 sp 的读写线程。

问题二:Google 系统为了确保数据的跨进程完整性,前期应用可以使用 sp 来做跨进程通信,在组件销毁或其他生命周期的同时为了确保当前这个写入任务必须在当前这个组件的生命周期完成写入,此时主线程会在组件销毁或者组件暂停的生命周期内等待 sp 完全写入到对应的文件中,如下图 UI 线程被 block 在了 QueuedWork.waitToFinish()处,接下来基于源码从 apply 开始到最后写入文件整体流程梳理找出问题根源。

具体需要等待文件写入的消息在 AcitivtyThread 的 H 中,具体消息类型如下:

public static final int SERVICE_ARGS = 115;
public static final int STOP_SERVICE = 116;
public static final int PAUSE_ACTIVITY = 101;
public static final int STOP_ACTIVITY_SHOW = 103;
public static final int SLEEPING  = 137;

由于 Google 官方设计之初是轻量级的数据存储方式,这种等待行为不会有什么问题,但是实际使用过程中由于 sp 过度使用,这个等待的时间被不可控的拉长,直到最后出现 ANR,这种问题越在业务繁重的应用上体现越明显。具体问题堆栈如下,全是系统堆栈,接下来从 waitToFinish 入手分析,剖析这个 ANR 的根源。具体 ANR 堆栈如下:

前期 sp 接口只有 commit 接口,接口同步写入文件,这个接口直接影响开发者使用,于是 Google 官方对外提供了异步的 apply 接口,由于开发者认为这个异步是真正意义上的异步,大规模的使用 sp 的 appy 接口,就是这种 apply 的实现方式导致了业务量大的 APP 深受这个 apply 设计缺陷导致的 ANR 问题影响。

apply 接口整体的详细设计思路如下图(基于 Android8.0 及以下版本分析):

整体的思路简单梳理如下:

  1. sp.apply(),写入内存同时得到需要同步写入文件的数据集合 MemoryCommitResult:

2 . 将 MemoryCommitResult 封装成 Runnable 抛到子线程 queued-work-looper 中; 3 . 在子线程中将 MemoryCommitResult 中的 mapToWriteToDisk 对应的 key-value 写入到文件中去; 4 . 文件写入完成以后,会执行 MemoryCommitResult 的 setDiskWriteResult 方法,关键的步骤 writtenToDiskLatch.countDown() 出现了; 5 . 如下当主线中执行到 QueuedWork.waitToFinish()的时候;

6 . 主线程到底在干什么,这个时候得从 QueuedWork.add(Runnable finisher)入手,具体 Runnable 如下图,这个地方就是啥也没干,直接等在了 mcr.writtenToDiskLatch.await()上,这里大家应该有点印象,就是步骤 4 中子线程在写完文件以后直接释放的那个锁

结论: 尽管整体 API 的流程分析异常的复杂,把一个 runnable 封装了一层又一层,从这个线程抛到那个线程,子线程执行完写入文件以后会释放锁,主线程执行到某些地方得等待子线程把写入文件的行为执行完毕,但是整体的思路还是比较简单的。造成这个问题的根源就是太多 pending 的 apply 行为没有写入到文件,主线程在执行到指定消息的时候会有等待行为,等待时间过长就会出现 ANR。

尽管 Google 官方在 Android 8.0 及以后版本对 sp 写入逻辑进行优化,期望是在上述步骤 6 中 UI 线程不是傻傻的等,而是帮助子线程一起写入,但是由于是保守协助,并没有很好的解决这个问题。

解决方案

问题一:针对加载很慢的问题,一般使用的比较多的是采用预加载的方式来触发到这个 sp 文件的加载和解析,这样在真正使用的时候大概率 sp 已经加载解析完毕了;真正需要处理的是核心场景的 sp 一定不能太大,Google 官方的声明还是有必要遵守一下,轻量级的数据持久化存储方式,不要存太多数据,避免文件过大,导致前期的加载解析耗时过久。

问题二:至于 Google 为什么要这么设计,提出了自己的几个猜想:

  1. Google 希望做到数据可能尽可能及时的写入文件,但是这样等待没有任何意义,主线程直接等待并不会提升写入的效率;
  2. 期望 sp 实时写入文件,以方便跨进程的时候可以实时的访问到 sp 内的文件,这种异步写入方式本身就没办法确保实时性;
  3. 可能是在组件发生状态切换的时候,这个时候如果进程内没有啥组件,进程的优先级可能降低,存在进程会在系统资源吃紧的时候被系统干掉,这种概率极低,几乎可以忽略不计;
  4. 感觉最大的可能性就是 Google 官方当时是为了从 commit 无缝的切换到 apply,依然模拟原来的 commit 行为,只是将原来的每次写入文件一次改成多次 commit 行为最后一次性 apply 在主线程等待所有的写入行为一次性全部写入。

通过以上假设,发现这里的主线程等待子线程写入根本没有什么意义,因此希望可以通过一些必要的手段跳过这种无用的等待行为,在研究了所有的 SharedPreference 相关的逻辑后找到以下入手点。以下是 8.0 以下版本的优化策略,8.0 及以上版本处理方式类似:

如果需要主线程在 waitToFinish 的时候直接跳过去,让 toTinish.run()执行完毕,显然不可能,如果能让 sPendingWorkFinishers.poll()返回为 null,则这里的等待行为直接就跳过去了,sPendingWorkFinishers 是个 ConcurrentLinkedQueue 集合,可以直接动态代理这个集合,复写 poll 方法,让其永远返回 null,这个时候 UI 永远不会等待子线程写入文件完毕。事实证明这种方式简单有效。

针对这种写入等待的 ANR 问题,还有一种就是全局替换写入方式,通过插桩的方式,替换所有的 API 实现,采用其他的存储方式,这种方式修复成本和风险较大,但是后期可以随机的替换存储方式,使用比较灵活。

方案收益

通过在字节系多个产品的验证,方案稳定有效,相应堆栈导致的 ANR 问题消灭殆尽,ANR 收益明显,相应的界面跳转等场景流畅性得到了明显的改善。

展望

Google 新增加了一个新 Jetpack 的成员 DataStore,主要用来替换 SharedPreferences, DataStore 应该是开发者期待已久的库,DataStore 是基于 Flow 实现的,一种新的数据存储方案。详细介绍网上有很多参考资料。

优化实践更多参考

  • [今日头条 ANR 优化实践系列(1)-设计原理及影响因素]
  • [今日头条 ANR 优化实践系列(2)-监控工具与分析思路]
  • [今日头条 ANR 优化实践系列(3)-实例剖析集锦]
  • [今日头条 ANR 优化实践系列(4)- Barrier 导致主线程假死]

本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/kfF83UmsGM5w43rDCH544g

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:1年以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:1年以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:1年以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:1年以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:1年以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:1年以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:1年以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:1年以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:1年以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:1年以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:1年以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:1年以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:1年以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:1年以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:1年以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:1年以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:1年以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:1年以前  |  398次阅读  |  详细内容 »
 相关文章
Android插件化方案 5年以前  |  237231次阅读
vscode超好用的代码书签插件Bookmarks 2年以前  |  8065次阅读
 目录