Memory leak专题

  • 神器:LeakCanary,memory leak检测工具;

Hanlder、Runnable、Thread的非静态内部类、匿名类,都会持有外部类的强引用,都可能造成内存泄漏;

  • Java的非静态内部类、匿名类,会持有外部类的强引用,静态的不会持有;对于Activity/Fragment内定义的Handler/Runnable,是最容易因此导致内存泄漏的,因为它们可能会postDelayed,从而导致Activity/Fragment及其内部的资源无法GC;推荐做法是定义静态内部类/静态匿名成员,访问外部类的成员和方法通过WeakRefrence实现;
  • WeakRefrence需要在内部类内创建才符合其语义?

Prior to Android Lollipop, alert dialogs may cause memory leaks in your Android apps.

  • 考虑以下代码
    while (true) {
     MyMessage msg = queue.take(); // might block
     System.out.println("Received: " + msg);
    }
    
    msg对象是栈上的局部变量,每次循环都将会重写,一旦被重写,上一次循环的msg引用指向的对象将不再被其引用;但是在Dalvik虚拟机的实现中,如果queue.take()阻塞了,那么本次循环的msg未被赋值,则上次的msg的引用将不会被清除,
  • HandlerThread
    for (;;) {
     Message msg = queue.next(); // might block
     if (msg == null) {
       return;
     }
     msg.target.dispatchMessage(msg);
     msg.recycleUnchecked();
    }
    
    msg每次循环的后面都被recycle了(清空了内容),所以泄漏的仅仅是一个空的msg对象,影响不大(LeakCanary将默认忽略Message对象的泄漏)。
  • 遇上AlertDialog
    new AlertDialog.Builder(this)
     .setPositiveButton("Baguette", new DialogInterface.OnClickListener() {
       @Override public void onClick(DialogInterface dialog, int which) {
         MyActivity.this.makeBread();
       }
     })
     .show();
    
    DialogInterface.OnClickListener的匿名实现类持有了MainActivity的强引用;而在AlertDialog的实现中,OnClickListener类将被包装在一个Message对象中,而且这个Message会在其内部被复制一份,两份Message中只有一个被recycle,另一个(OnClickListener的成员变量引用的Message对象)将会leak!
  • 解决办法
    • ART VM(>=5.0),JVM不存在此问题
    • Message对象的泄漏无法避免,但是如果仅仅是一个空的Message对象,而且将被放入对象池作为后用,是没有问题的
    • DialogInterface.OnClickListener对象不持有外部类的强引用:static类实现;DetachableClickListener(监听窗口解除事件,手动释放引用);
    • 当worker thread空闲后,向HandlerThread发送一个空的消息,解除上一个Message的泄漏

results matching ""

    No results matching ""