activity的 static 成员 造成的内存泄漏
static TestView sTextView 由于要setText ,所以持有了一个对 Context
的引用,这使得一旦这个 Activity不在了之后,sTextView 依然会 hold 住 Context
不放,所以即便activity的生命周期结束了,它也不能释放。
关于Handler post delay 的内存泄漏
Android Lint 和 LeakCanary都没有检测出来。原因可能是这里并算不上是真正的内存泄漏吧。
用自己的语言说一下对handler内存泄漏的理解
- activity中的成员mHandler指向的handler被调用post delay的时候,把一个runable对象放到了当前线程的消息队列中,这个runable是activity一个非静态的内部匿名类对象,设计上因为这个内部类对象它可以访问activity的成员,因此,实现上需要持有一个对activity的强引用。
- UI主线程中的message queue 挂上了这个runnable,那么除非该runnable 被使用了,否则它不会从queue中移除。而这个queue是在整个UI线程,也就是整个程序生命周期中都存在的,所以,一个长生命周期的指针指向的本来是短生命周期的对象,也就没法释放。反复多次,会造成内存泄漏。当然这个也不算严格意义上的内存泄漏,因为它毕竟是有机会释放的。
https://techblog.badoo.com/blog/2014/08/28/android-handler-memory-leaks
文章中提供了如下三种解决方法:
- 使用静态内部Handler/Runnable + 弱引用
这种方法的原理其实我现在理解还是模糊的,使用起来也不方便。
- 在onDestory的时候,手动清除Message
相当于把handler直接从message queue中移除了。
这样之前未完成的handler事情就不做了。
- 使用Badoo开发的第三方的 WeakHandler
大量创建新对象
private void startAllocationLargeNumbersOfObjects() {
for (int i = 0; i < 10000; i++) {
Rect rect = new Rect(0, 0, 100, 100);//这段代码创建了多个Rect对象,会造成内存上升,但并不会发生内存泄漏,通过GC可以释放。
//正常情况下这么写代码很少见。一个常见的错误例子是在listview 的getView里面每次都申请一个view而不是复用。
}