8.优化 - 内存监控分析

内存问题大致可分为内存溢出内存泄露二大类。

  • 内存溢出(Out Of Memory) :就是申请内存时,剩余的空间(经过GC)没有足够的内存进行分配。
  • 内存泄露 (Memory Leak):就是申请了内存,但是没有释放,导致内存空间浪费。

  对于内存溢出问题,一般是由于一次申请一块大内存、无数次申请小内存、创建过多线程、打开文件未关闭等等所引起,对于不同的原因引起的可以采用不同方式去监控告警处理。比如对于创建线程、打开文件未关闭的可以 hook 其创建线程、打开关闭文件时记录,并在进程结束时判断那些是打开未关闭的,但是对于内存分配来说,监控内存分配好像没有什么意义。
  而内存泄露问题是由于生命周期长的对象持有了生命周期短的对象,导致生命周期短的对象没有办法及时释放内存,在 Android 中最经典的就是 activity 被 handle 的 msg 持有,而 msg 又在 app 进程的 msgqueue 中,没有执行 msg 就不会释放所持有的 activity 。

  在本地可以使用 AS 自带的 profiler 很方便的来查看内存相关的东西,也可以记录下内存放到分析工具如 MAT 来分析。
  而在线上实现起来有点困难,难在在什么时机去拿内存快照,怎么去拿内存快照及拿到之后需不需要本地分析、裁剪上传等问题。在网络上及大厂分享中有对这些问题比较完美的的解决方案。

拿内存快照的时机
  • 类似与 LeakCanary 方案,主要监控 activity 和 fragment,原理是在 Activity.onDestroy() 后连续触发GC,并检查引用队列,判定 Activity 是否发生了泄漏,没有被回收则执行拿内存快照的操作。
  • 美团分享及快手 KOOM 的方案,轮训去检测内存的使用,当依次从低到高达到阈值或突然到95%的使用时触发去内存快照操作。
怎么去拿内存快照

在 Android 中,可以用过 Debug.dumpHprofData("path") 来得到内存快照,但是这个过程一般会持续几秒到几十秒不等,为保持现场信息,在这个过程中会挂起所有的线程来进行,所以 dump 的过程中不可操作 app。

  • 在子线程去拿内存快照,缺点在上方。
  • 利用 Linux 的 Copy-On-Write 机制。挂起当前进程,开一个子进程之后恢复主进程,在子进程中拿内存快照,可以不影响到主线程的使用,卡顿的时间(fork 子进程的时间)几乎可以不计。
快照裁剪

对于内存快照的处理,一般有本地分析和传回后台分析两种。而快照的大小轻轻松松就可以达到 100MB 以上,无论是本地分析还是上传都需要对快照进行裁剪,删除其中无用的信息。

  • 直接对 dump 的快照进行裁剪。但是很不幸的是当快照过大时再次触发OOM,直接GG。
  • 在 dump 的过程中对快照进行裁剪。可以 hook 系统的 write 函数,当判断写入的是快照内容时直接进行裁剪。
快照分析

根据业务需求即可,使用 LeakCanary 使用的 haha 库或 shark 库,或者自己根据 hprof 文件格式自己分析都可。

参考:
Koom 解决hprof文件过大-源码解析
微信 Android 终端内存优化实践
快手客户端稳定性体系建设
java hprof 文件格式
...

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容