序、慢慢来才是最快的方法。
LeakCanary系列
背景
LeakCanary是Square的开源库,通过弱引用方式侦查Activity或Fragment对象的生命周期,若发现内存泄漏自动 dump Hprof文件,通过HAHA库得到泄露的最短路径,最后通过Notification展示。
简单说就是在在Activity对象onDestory的时候,新建一个WeakReference对象指向Activity对象,如果Activity对象被垃圾回收的话,WeakReference对象就会进入引用序列的ReferenceQueue。
所以我们只需要在Activity对象OnDestory之后去查看ReferenceQueue序列是否有该WeakReference对象即可。
第一次观察是Activity的onDestory5秒后,如果发现ReferenceQueue对来还没有WeakReference对象,就进入第二次观察,如果有了,就证明没有泄漏,第二次观察跟第一次观察相比区别在于会先进行垃圾回收,在进行ReferenceQueue序列的观察。
问题
LeakCanary只能用在测试阶段,但是我们都知道,线上才是我们真正的战场。接下来简单分析一下如果自定义LeakCanary做一个线上的内存检测。继承DisplayLeakService类,重写afterDefaultHandling()方法,实现自己的内存泄漏信息保存。
1.在初始化的时候,构建者传入的DisplayLeakService就是分析内存泄漏的地方
public static RefWatcher install(Application application) {
return refWatcher(application).listenerServiceClass(DisplayLeakService.class)
.excludedRefs(AndroidExcludedRefs.createAppDefaults().build())
.buildAndInstall();
}
2.继承DisplayLeakService
class WanAndroidLeakService extends DisplayLeakService {
@Override
protected void afterDefaultHandling(HeapDump heapDump, AnalysisResult result, String leakInfo) {
super.afterDefaultHandling(heapDump, result, leakInfo);
//拿到内存泄露的分析结果
boolean leakFound = result.leakFound;
boolean excludedLeak = result.excludedLeak;
String className = result.className;
LeakTrace leakTrace = result.leakTrace;
Throwable failure = result.failure;
long retainedHeapSize = result.retainedHeapSize;
long analysisDurationMs = result.analysisDurationMs;
}
}
为什么不能用于线上
- 每次内存泄漏以后,都会生成一个
.hprof
文件,然后解析,并将结果写入.hprof.result
。增加手机负担,引起手机卡顿等问题。 - 多次调用
GC
,可能会对线上性能产生影响 - 同样的泄漏问题,会重复生成
.hprof
文件,重复分析并写入磁盘。 .hprof
文件较大,信息回捞成问题。
尝试一下解决方案
- 可以根据手机信息来设定一个内存阈值
M
,当已使用内存小于M
时,如果此时有内存泄漏,只将泄漏对象的信息放入内存当中保存,不生成.hprof
文件。当已使用大于M
时,生成.hprof
文件 - 当引用链路相同时,可根据实际情况去重。
- 不直接回捞
.hprof
文件,可以选择回捞分析的结果 - 可以尝试将已泄漏对象存储在数据库中,一个用户同一个泄漏只检测一次,减少对用户的影响
参考
Android 开源库 #7 为什么各大厂自研的内存泄漏检测框架都要参考 LeakCanary?因为它是真强啊!