handle内存泄漏

112 阅读2分钟

handle引用链:threadlocal-》looper-》messagequeue-》message-》handle-》activity

handle引用链详解:

handle持有activity(内部类持有外部类的饮用)

mag.tag持有handle对象( msg.target = this;)

private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,long uptimeMillis) {
    msg.target = this;
    msg.workSourceUid = ThreadLocalWorkSource.getUid();
  if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

messagequeue持有message对象

looper持有messagequeue(loop构造方法中创建messagequeue)

threadlocal作为一个map集合持有looper(looper的prepare方法中,threadlocal.set(new looper())

threadlocal是static关键字修饰的静态变量(static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); ),生命周期与应用程序一样,threadlocal是一个gcRoots引用链,可达分析法gcroots引用的对象不可以被回收,由于sThreadLocal是GC Root,activity是可达的,所以activity不会被回收,就会造成内存泄漏。

在java中,可以作为GC Roots的对象主要有以下几种:
1.java栈中引用的对象
2.本地方法栈中JNI引用的对象
3.方法区中运行时常量池引用的对象
4.方法区中静态属性引用的对象
5.运行中的线程
6.由引导类加载器加载的对象
7.GC控制的对象

handle内存泄漏解决办法:

1.静态内部类+弱引用 修改Handler为static类,并使用弱引用,这样才能在静态内部类中调用外部类方法。
此种方式是打断handler->activity。因为java静态匿名内部类不会持有外部类引用。

	private final WeakReference<MineActivity> mMineActivityWeak;
	public MyHandler(MineActivity mineActivity){
		mMineActivityWeak = new WeakReference<>(mineActivity);
	}
	@Override
	public void handleMessage(@NonNull Message msg) {
		super.handleMessage(msg);
		MineActivity mineActivity = mMineActivityWeak.get();
		if(mineActivity != null){
			mineActivity.number = 5;
        }
    }
}
  1. 在activity.onDestory()方法中,将messageQueue中的消息清除掉。
    此种方式是打断messageQueue->message。

  @Override
  protected void onDestroy() {
    super.onDestroy();
    mHandler.removeCallbacksAndMessages(null);

  }

 
  //Handler源码中removeCallbacksAndMessages()注释含义
  /**
   * Remove any pending posts of callbacks and sent messages whose
   * <var>obj</var> is <var>token</var>. If <var>token</var> is null,
   * all callbacks and messages will be removed.
   */
  public final void removeCallbacksAndMessages(Object token) {
    mQueue.removeCallbacksAndMessages(this, token);
  }