2021-11-12 18:55:55
内存泄露的根本原因在于Java对象未被及时回收,导致内存资源浪费。要理解这一问题,需要对Java的垃圾回收机制有所了解。垃圾回收机制在运行时会自动清理无用对象以释放内存。Java虚拟机通过GC ROOT可达性算法判断对象是否被使用。若一个对象能通过GC ROOT路径到达,则认为其为有用对象,否则为无用对象。
内存泄露问题与引用类型密切相关。Java中有四种引用类型,分别定义了对象的存活条件和生命周期:
强引用:对象通过new创建,只要强引用存在,垃圾回收器不会回收该对象。
软引用:系统在发生内存溢出前,会将这些对象列入回收范围,进行第二次回收。
弱引用:对象只能存活至下一次垃圾回收发生前。
虚引用:无生存时间限制,不能通过虚引用获取对象实例,用于在对象被回收时收到通知。
若对象通过强引用存在且GC ROOT不可达,垃圾回收器无法回收该对象,导致内存泄露。内存泄露意味着对象无实际用途,却占用内存资源,造成资源浪费。
为实现内存泄露检测,可以利用弱引用与引用队列的特性。通过创建与引用队列关联的WeakReference对象,在对象被GC回收时,将引用存入引用队列。检测引用队列中的值,若一直为null,表示存在内存泄露。
LeakCanary正是利用此原理检测内存泄露。当用户退出Activity时,Activity对象通常会被系统回收。LeakCanary在Activity的onDestroy回调中保存Activity对象到WeakReference,并关联引用队列。通过检测引用队列,可以发现内存泄露。
LeakCanary的源码分析涉及自动初始化和类型检测。MainProcessAppWatcherInstaller自动安装LeakCanary,简化引入成本。AppWatcher在安装时处理不同类型的InstallableWatcher。ActivityWatcher在Activity生命周期中监控,当Activity销毁时,触发内存泄露检测过程。LeakCanary通过ObjectWatcher的expectWeaklyReachable函数,动态检查和记录内存泄露情况。
内存泄露检测的源码实现相对简单,难点在于泄露链路分析和内存泄露报告的生成。这部分内容在本文中未深入探讨,但后续有机会会单独讲解。