记录一次切换语言造成卡顿的分析(内存泄漏造成内存溢出)

前言

首先有两个概念
内存溢出(Out of Memory):系统会给每个APP分配内存也就是Heap Size值。当APP占用的内存加上我们申请的内存资源超过了Dalvik虚拟机的最大内存时就会抛出的Out Of Memory异常。

内存泄漏(Memory Leak):当一个对象不在使用了,本应该被垃圾回收器(JVM)回收。但是这个对象由于被其他正在使用的对象所持有,造成无法被回收的结果。内存泄漏最终会导致内存溢出。

内存泄漏的原因有很多,如Handler错误使用,线程隐式引用Context,单例中对象的引用,未关闭某个资源,非静态内部类创建静态实例等等,归根结底是对象一直被持有无法回收导致的泄漏。

卡顿的问题分析

收到反馈卡顿的问题时,由于无现场,只能通过分析log,在log中发现频繁的切换语言,应用多次初始化的操作。
手动切换语言,切换语言后返回应用。通过dumpsys meminfo查看内存占用情况,发现主界面应用内存持续增长。确定某个应用后也可通过dumpsys meminfo 应用包名查看应用的内存情况。

Applications Memory Usage (kB): Uptime: 132024 Realtime: 132024

Total PSS by process:
2264679 kB: com.example.launcher (pid 2016 / activities)
44066 kB: com.android.systemui (pid 1852)
43701 kB: system (pid 1773)
11101 kB: android.process.media (pid 2180)
10902 kB: com.android.phone (pid 1995)
8531 kB: com.android.inputmethod.pinyin (pid 1974)
8390 kB: com.android.providers.calendar (pid 2290)
8059 kB: mediaserver (pid 2284)
7879 kB: android.process.acore (pid 2069)
6870 kB: com.google.android.webview:webview_service (pid 2209)
5972 kB: zygote (pid 1479)
5721 kB: com.android.managedprovisioning (pid 2332)
5337 kB: com.android.keychain (pid 2264)
5318 kB: com.android.printspooler (pid 2033)
5126 kB: com.android.onetimeinitializer (pid 2352)
1884 kB: surfaceflinger (pid 1466)
1426 kB: wpa_supplicant (pid 1963)
1070 kB: drmserver (pid 1473)
846 kB: logd (pid 1460)
792 kB: vold (pid 1465)
719 kB: keystore (pid 1477)
695 kB: netd (pid 1470)
597 kB: rild (pid 1472)
577 kB: su (pid 2484)
554 kB: sdcard (pid 1410)
544 kB: adbd (pid 1462)
480 kB: healthd (pid 1461)
479 kB: /init (pid 1)
408 kB: lmkd (pid 1463)
353 kB: logcat (pid 2474)
344 kB: debuggerd (pid 1471)
343 kB: installd (pid 1475)
342 kB: ueventd (pid 1012)
326 kB: dhcpcd (pid 2107)
291 kB: servicemanager (pid 1464)

Total PSS by OOM adjustment:
27101 kB: Native
8059 kB: mediaserver (pid 2284)
5972 kB: zygote (pid 1479)
1884 kB: surfaceflinger (pid 1466)
1426 kB: wpa_supplicant (pid 1963)
1070 kB: drmserver (pid 1473)
846 kB: logd (pid 1460)
792 kB: vold (pid 1465)
719 kB: keystore (pid 1477)
695 kB: netd (pid 1470)
597 kB: rild (pid 1472)
577 kB: su (pid 2484)
554 kB: sdcard (pid 1410)
544 kB: adbd (pid 1462)
480 kB: healthd (pid 1461)
479 kB: /init (pid 1)
408 kB: lmkd (pid 1463)
353 kB: logcat (pid 2474)
344 kB: debuggerd (pid 1471)
343 kB: installd (pid 1475)
342 kB: ueventd (pid 1012)
326 kB: dhcpcd (pid 2107)
291 kB: servicemanager (pid 1464)

由于项目的MVP架构存在着context滥用的问题,一旦出现一些异常操作非常容易出现内存泄漏。
追踪代码,发现MVP的P层实例化在onCreate执行,每次执行都会初始化一次导致内存泄漏,内存持续增加直至内存溢出,从而导致系统卡顿。

2022-05-06 21:42:04.634 5226-5226/com.example.systemapp D/test: onDestroy
2022-05-06 21:42:04.787 5226-5226/com.example.systemapp D/test: onCreate
2022-05-06 21:42:04.788 5226-5226/com.example.systemapp D/test: onStart
2022-05-06 21:42:04.789 5226-5226/com.example.systemapp D/test: onResume

解决方案

首先需要在单例初始化中增加防抖策略,避免重复初始化。
接下来有两种方案:
方案一:
不在onCreate初始化单例,改在Application中初始化。由于需要在onDestroy中进行反注册操作。所以采用下面的方案。
方案二:
在AndroidManfest中增加配置,不让其切换语言后重走onCreate方法。
这里考虑了两种方案,配置configChanges属性:

android:configChanges=“locale|layoutDirection|keyboardHidden”

配置后需要考虑语言问题,需要动态设置资源以便切换对应语言文本。
声明了configChanges在组件中会回调onConfigurationChanged方法,不会再次重新onCreate。可重写onConfigurationChanged进行资源动态设置。

2022-05-06 19:27:15.414 4464-4464/com.example.systemapp D/test: onConfigurationChanged
2022-05-06 19:27:15.415 4464-4464/com.example.systemapp D/test: onStart
2022-05-06 19:27:15.415 4464-4464/com.example.systemapp D/test: onResume

归根结底还是项目中Context的使用不当,对象避免一直持有Context引用,单例中Context则应该为ApplicationContext,才能对应整个应用的生命周期。这样Activity回收后才不会被一直被持有。
这次的卡顿现象由于存在规律,通过log发现复现手法,未借助其他工具分析,通过dumpsys meminfo或top等指令即可查看内存资源占用情况,通过此指令排查应用占用系统资源来定位哪个应用的问题。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

言并肃

感谢大哥支持!您的鼓励是我动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值