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

2024-01-02 20:44

本文主要是介绍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>? = nullfun 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? = nulloverride 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? = nulltry {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? = nulloverride 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? = nulloverride 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!

这篇关于LeakCanary 最新版 2.12 内存泄露工具使用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/563602

相关文章

使用Python实现一键隐藏屏幕并锁定输入

《使用Python实现一键隐藏屏幕并锁定输入》本文主要介绍了使用Python编写一个一键隐藏屏幕并锁定输入的黑科技程序,能够在指定热键触发后立即遮挡屏幕,并禁止一切键盘鼠标输入,这样就再也不用担心自己... 目录1. 概述2. 功能亮点3.代码实现4.使用方法5. 展示效果6. 代码优化与拓展7. 总结1.

使用Python开发一个简单的本地图片服务器

《使用Python开发一个简单的本地图片服务器》本文介绍了如何结合wxPython构建的图形用户界面GUI和Python内建的Web服务器功能,在本地网络中搭建一个私人的,即开即用的网页相册,文中的示... 目录项目目标核心技术栈代码深度解析完整代码工作流程主要功能与优势潜在改进与思考运行结果总结你是否曾经

Linux中的计划任务(crontab)使用方式

《Linux中的计划任务(crontab)使用方式》:本文主要介绍Linux中的计划任务(crontab)使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、前言1、linux的起源与发展2、什么是计划任务(crontab)二、crontab基础1、cro

kotlin中const 和val的区别及使用场景分析

《kotlin中const和val的区别及使用场景分析》在Kotlin中,const和val都是用来声明常量的,但它们的使用场景和功能有所不同,下面给大家介绍kotlin中const和val的区别,... 目录kotlin中const 和val的区别1. val:2. const:二 代码示例1 Java

C++变换迭代器使用方法小结

《C++变换迭代器使用方法小结》本文主要介绍了C++变换迭代器使用方法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1、源码2、代码解析代码解析:transform_iterator1. transform_iterat

C++中std::distance使用方法示例

《C++中std::distance使用方法示例》std::distance是C++标准库中的一个函数,用于计算两个迭代器之间的距离,本文主要介绍了C++中std::distance使用方法示例,具... 目录语法使用方式解释示例输出:其他说明:总结std::distance&n编程bsp;是 C++ 标准

vue使用docxtemplater导出word

《vue使用docxtemplater导出word》docxtemplater是一种邮件合并工具,以编程方式使用并处理条件、循环,并且可以扩展以插入任何内容,下面我们来看看如何使用docxtempl... 目录docxtemplatervue使用docxtemplater导出word安装常用语法 封装导出方

Linux换行符的使用方法详解

《Linux换行符的使用方法详解》本文介绍了Linux中常用的换行符LF及其在文件中的表示,展示了如何使用sed命令替换换行符,并列举了与换行符处理相关的Linux命令,通过代码讲解的非常详细,需要的... 目录简介检测文件中的换行符使用 cat -A 查看换行符使用 od -c 检查字符换行符格式转换将

使用Jackson进行JSON生成与解析的新手指南

《使用Jackson进行JSON生成与解析的新手指南》这篇文章主要为大家详细介绍了如何使用Jackson进行JSON生成与解析处理,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 核心依赖2. 基础用法2.1 对象转 jsON(序列化)2.2 JSON 转对象(反序列化)3.

使用Python实现快速搭建本地HTTP服务器

《使用Python实现快速搭建本地HTTP服务器》:本文主要介绍如何使用Python快速搭建本地HTTP服务器,轻松实现一键HTTP文件共享,同时结合二维码技术,让访问更简单,感兴趣的小伙伴可以了... 目录1. 概述2. 快速搭建 HTTP 文件共享服务2.1 核心思路2.2 代码实现2.3 代码解读3.