LeakCanary 最新版 2.12 内存泄露工具使用

1. 在使用LeakCanary之前,我们需要添加下面的依赖:

dependencies {
  // debugImplementation 是因为 LeakCanary 应该只工作在 debug 编译环境.
  debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.12'
}

2. 如果我们需要观察LeakCanary是否启动,只需要在日志中过滤LeakCanary 即可。

LeakCanary xxx D  LeakCanary is running and ready to detect memory leaks.

3. LeakCanary2.12 会自动侦测下列对象的内存泄露情况:

  • destroyed Activity instances
  • destroyed Fragment instances
  • destroyed fragment View instances
  • cleared ViewModel instances
  • destroyed Service instance

4. 我们知道内存泄漏的情况可能有以下情况:

  1. 静态变量引用的内存泄露:

如果一个对象被持久地引用,并存储在静态变量中,那么即使Activity或Fragment已经被销毁,该对象仍然存在于内存中,从而导致内存泄露。为了避免这种情况,应该避免在静态变量中持有Activity或Fragment的引用。

class MySingleton {
    companion object {
        var instance: Activity? = null
    }
}

// 在Activity中持有了MySingleton的引用
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        MySingleton.instance = this
    }
}

改:

class MySingleton {
    companion object {
        private var instance: WeakReference<MainActivity>? = null

        fun getInstance(): MainActivity? {
            return instance?.get()
        }

        fun setInstance(activity: MainActivity) {
            instance = WeakReference(activity)
        }
    }
}

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        MySingleton.setInstance(this)
    }
}
  1. 非静态内部类的隐式引用的内存泄露:

非静态内部类默认会持有外部类的引用,如果非静态内部类的实例被持久地引用,那么外部类也无法被GC回收,从而导致内存泄露。可以将非静态内部类声明为静态内部类,或者使用弱引用(WeakReference)来解决这个问题。

class OuterClass {
    // 非静态内部类,默认持有外部类的引用
    inner class InnerClass {
        fun doSomething() {
            // 执行一些操作
        }
    }
}

// 在Activity中持有了InnerClass的引用
class MainActivity : AppCompatActivity() {
    private val innerClass: OuterClass.InnerClass = OuterClass().InnerClass()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        innerClass.doSomething()
    }
}

改:

class OuterClass {
    // 非静态内部类,默认持有外部类的引用
    static inner class InnerClass {
        fun doSomething() {
            // 执行一些操作
        }
    }
}

class MainActivity : AppCompatActivity() {
    private val innerClass: OuterClass.InnerClass? = OuterClass().InnerClass()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        innerClass?.doSomething()
    }
}
  1. 未取消注册的监听器的内存泄露:

如果在Activity或Fragment中注册了监听器(如广播接收器、触摸事件监听器等),在不再需要监听器时忘记取消注册,就会导致内存泄露。为了避免这种情况,应该在不需要监听器时及时取消注册。

class MyBroadcastReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        // 接收到广播后执行一些操作
    }
}

// 在Activity中注册了广播接收器,但没有在合适的时机取消注册
class MainActivity : AppCompatActivity() {
    private val receiver: MyBroadcastReceiver = MyBroadcastReceiver()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val filter = IntentFilter()
        filter.addAction("com.example.ACTION")
        registerReceiver(receiver, filter)
    }
}

改:

class MyBroadcastReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        // 接收到广播后执行一些操作
    }
}

class MainActivity : AppCompatActivity() {
    private var receiver: MyBroadcastReceiver? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val filter = IntentFilter()
        filter.addAction("com.example.ACTION")
        receiver = MyBroadcastReceiver()
        registerReceiver(receiver, filter)
    }

    override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(receiver)
        receiver = null
    }
}
  1. 资源未关闭的内存泄露:

在使用一些需要手动关闭的资源(如数据库连接、文件输入输出流等)时,如果忘记关闭这些资源,就会导致内存泄露。为了避免这种情况,应该在不再需要资源时及时关闭它们。

class FileOperation {
    fun readFile() {
        val file = File("example.txt")
        val inputStream = FileInputStream(file)

        // 读取文件内容
        // ...

        // 忘记关闭文件输入流
    }
}

// 在Activity中执行文件读取操作,但忘记关闭文件输入流
class MainActivity : AppCompatActivity() {
    private val fileOperation: FileOperation = FileOperation()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        fileOperation.readFile()
    }
}

改:

class FileOperation {
    fun readFile() {
        val file = File("example.txt")
        var inputStream: FileInputStream? = null
        try {
            inputStream = FileInputStream(file)

            // 读取文件内容
            // ...
        } catch (e: IOException) {
            e.printStackTrace()
        } finally {
            inputStream?.close()
        }
    }
}

class MainActivity : AppCompatActivity() {
    private val fileOperation: FileOperation = FileOperation()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        fileOperation.readFile()
    }
}
  1. 异步任务未取消的内存泄露:

如果在Activity或Fragment中启动了异步任务(如AsyncTask、线程等),并且在Activity或Fragment被销毁时没有取消这些任务,就会导致内存泄露。为了避免这种情况,应该在Activity或Fragment的生命周期方法中及时取消异步任务。

class MyAsyncTask : AsyncTask<Void, Void, String>() {
    override fun doInBackground(vararg params: Void?): String {
        // 执行一些耗时操作
        return "result"
    }
}

// 在Activity中启动异步任务,但没有在合适的时机取消任务
class MainActivity : AppCompatActivity() {
    private var asyncTask: MyAsyncTask? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        asyncTask = MyAsyncTask().execute()
    }
}

改:

class MyAsyncTask(private val activity: WeakReference<MainActivity>) :
    AsyncTask<Void, Void, String>() {

    override fun doInBackground(vararg params: Void?): String {
        // 执行一些耗时操作
        return "result"
    }

    override fun onPostExecute(result: String?) {
        super.onPostExecute(result)

        val activity = activity.get()
        if (activity != null && !activity.isFinishing) {
            // 处理任务结果
        }
    }
}

class MainActivity : AppCompatActivity() {
    private var asyncTask: MyAsyncTask? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        asyncTask = MyAsyncTask(WeakReference(this)).execute()
    }

    override fun onDestroy() {
        super.onDestroy()
        asyncTask?.cancel(true)
        asyncTask = null
    }
}

Thank you for your reading, best regards!

你可能感兴趣的:(小tips,android)