09. handler 内存泄漏的原因
2022年4月16日
09. handler 内存泄漏的原因
什么是内存泄漏?
本该回收的对象,停留在内存中没被回收。
为什么没被回收?
有正在使用的对象持有他的引用,所以没被回收。
Handler为什么会有这种情况?
- 使用Handler非静态内部类(匿名内部类也是)创建的实例,内部类会隐式持有外部类的引用,也就是Handler会持有Activity的引用。
- 当handler发送Message消息时,我们知道,Message会持有Handler(target)引用,Message消息进入消息队列,队列里没有就加到头部,有就根据时间插入。 looper循环从队列里获取消息,处理分发的时候会做阻塞操作,如果队列中的消息未处理完,Activity被关闭,GC是无法回收Activity的,从而造成内存泄露。
解决方法
- 使用静态内部类或外部类: 移除了隐式引用。如需持有外部对象,应将handler持有的对象改成弱引用(WeakReference)。
- 弱引用的对象拥有短暂的生命周期,在垃圾回收器线程扫描时,一旦发现了具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存.
- mHandler 通过弱引用的方式持有Activity,当GC 执行垃圾回收时,遇到Activity就会回收并释放所占据的内存单元。这样就不会发生内存泄露了。
- GC在回收时会忽略掉弱引用对象(忽略掉这种引用关系),即:就算弱引用指向了某个对象,但只要该对象没有被强引用指向,该对象也会被GC检查时回收掉。
就会回收并释放所占据的内存单元。这样就不会发生内存泄露了。
- 外部类生命周期结束时,清空Handler内的消息。 mHandler.removeCallbacksAndMessages(null);
强/弱/软/虚引用
强引用就是对象被强引用后,无论如何都不会被回收。 弱引用就是在垃圾回收时,如果这个对象只被弱引用关联(没有任何强引用关联他),那么这个对象就会被回收。 软引用就是在系统将发生内存溢出的时候,回进行回收。 虚引用是对象完全不会对其生存时间构成影响,也无法通过虚引用来获取对象实例,用的比较少。
引用被划为4种级别,强引用,软引用,弱引用,虚引用。
- 我们做常用的就是强引用
- 软引用在内存不足时回收
SoftReference softReference = new SoftReference(对象);
- 弱引用:垃圾回收期扫描时,一旦发现了弱引用对象,不管内存是否足够,都会回收。
String str = new String("abc");
WeakReference<String> weakReference = new WeakReference<>(str);
// 弱引用转强引用
String strongReference = weakReference.get();
- 虚引用:虚引用主要用来跟踪对象被垃圾回收器回收的活动。 可以跟踪对象是否被加入引用队列。