zgq105 / blog

2 stars 0 forks source link

Android内存泄漏GC Root分析总结 #107

Open zgq105 opened 10 months ago

zgq105 commented 10 months ago

1. 内存泄漏的原因?

内存泄漏的本质是长生命周期的对象持有短生命周期对象的引用,导致本应该被回收的短生命周期对象不能被GC回收导致内存泄漏。

2. Hander内存泄漏分析?

class BActivity : AppCompatActivity() {

    inner class MyHandler : Handler(Looper.getMainLooper()) {
        override fun handleMessage(msg: Message) {
            super.handleMessage(msg)
            Log.d("zgq", "handleMessage:${msg.what}")
        }
    }

   private val myHandler = MyHandler()
   override fun onResume() {
        super.onResume()
        //模拟handler内存泄漏,启动页面然后马上关闭页面
        myHandler.sendEmptyMessageDelayed(1103, 20 * 1000)
   }

}

从上面这里实例代码我们知道可以通过Profiler或者leakcanary都会发现内存泄漏了,通过阅读源码可以知道以下的引用链:

ActivityThread中主线程 -> ThreadLocalMap -> ThreadLocal -> Looper -> MessageQueue -> Message -> Handler -> Activity

因为主线程是一直存在的,导致引用链不能被回收,进而导致Activity 实例发生内存泄漏的根本原因。GC Root引用链已经列出来了,重点查看以上相关的源码还是很好理解的。所以这里的GC Root主线程对象。

3.线程内存泄漏分析?

class BActivity : AppCompatActivity() {

    inner class MyHandler : Handler(Looper.getMainLooper()) {
        override fun handleMessage(msg: Message) {
            super.handleMessage(msg)
            Log.d("zgq", "handleMessage:${msg.what}")
        }
    }

   private val myHandler = MyHandler()
   override fun onResume() {
        super.onResume()
       //模拟子线程内存泄漏,启动页面然后马上关闭页面
        Thread {
            Thread.sleep(20 * 1000)
            myHandler.sendEmptyMessage(11)
            Log.d("zgq", "thread:end")
        }.start()
   }

}

按相同的方式分析以上代码的引用链是:子线程 -> Handler -> Activity ,因为这里是子线程对象引用了Handler对象 ,而Handler 对象又引用了Activity对象,导致内存泄漏;这里的GC Root就是子线程的实例对象。