一句话总结:
内存泄漏就是“垃圾赖着不走”,本该被回收的对象被其他对象“强行挽留”,导致内存占用越来越高,最终应用卡死或崩溃!
一、内存泄漏的常见场景(为什么会赖着不走?)
1. 匿名内部类(比如 Handler、Runnable)
-
问题代码:
class MyActivity : AppCompatActivity() { private val handler = Handler(Looper.getMainLooper()) { // 处理消息(隐式持有 Activity 的引用) true } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 发送延迟消息 handler.postDelayed({ updateUI() }, 100000) // 延迟 100 秒 } } -
原因:
Handler匿名内部类隐式持有MyActivity的引用,若在Activity销毁前未移除消息,Activity无法被回收。
2. 单例模式持有 Context
-
问题代码:
object SingletonManager { private var context: Context? = null fun init(context: Context) { this.context = context // 传入了 Activity 的 Context } } -
原因:单例的生命周期与应用一致,若持有
Activity的Context,Activity销毁后无法释放。
3. 静态变量引用 View 或 Activity
-
问题代码:
class MyActivity : AppCompatActivity() { companion object { var staticView: View? = null // 静态变量持有 View } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) staticView = findViewById(R.id.my_view) } } -
原因:静态变量生命周期过长,导致
View关联的Activity无法回收。
4. 未反注册监听器(如广播、回调)
-
问题代码:
class MyActivity : AppCompatActivity() { private val receiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { // 处理广播 } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) registerReceiver(receiver, IntentFilter("MY_ACTION")) } // 忘记在 onDestroy 中反注册! } -
原因:
BroadcastReceiver注册后未反注册,系统会一直持有Activity的引用。
二、如何查找内存泄漏?(抓赖账的垃圾)
1. 使用 LeakCanary(自动检测神器)
-
步骤:
-
添加依赖:
dependencies { debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.12' } -
无需额外代码,应用运行后,LeakCanary 自动检测泄漏并弹出通知。
-
查看报告,定位泄漏对象和引用链。
-
2. 使用 Android Studio Profiler(手动分析)
-
步骤:
- 点击 Android Studio 底部的 Profiler → 选择 Memory。
- 操作应用进入怀疑泄漏的页面,然后返回。
- 点击 Dump Java Heap 生成堆转储文件。
- 在 Heap Dump 中搜索疑似泄漏的类(如 Activity),查看引用路径。
3. 手动排查(土法炼钢)
-
检查点:
- 所有
Handler、Runnable是否在onDestroy中移除回调。 - 单例、静态变量是否持有
Context或View。 - 监听器、广播、服务是否反注册。
- 所有
三、如何解决内存泄漏?(赶走赖账的垃圾)
1. 匿名内部类改用静态内部类 + 弱引用
-
修复代码:
class MyActivity : AppCompatActivity() { private val handler = MyHandler(this) // 静态内部类,不隐式持有 Activity private class MyHandler(activity: MyActivity) : Handler(Looper.getMainLooper()) { private val weakActivity = WeakReference(activity) override fun handleMessage(msg: Message) { weakActivity.get()?.updateUI() } } override fun onDestroy() { super.onDestroy() handler.removeCallbacksAndMessages(null) // 移除所有消息 } }
2. 单例模式使用 Application Context
-
修复代码:
object SingletonManager { private var context: Context? = null // 传入 Application Context fun init(context: Context) { this.context = context.applicationContext } }
3. 静态变量避免引用 View/Activity
-
修复代码:
class MyActivity : AppCompatActivity() { // 改用弱引用 companion object { private var weakView: WeakReference<View>? = null } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) weakView = WeakReference(findViewById(R.id.my_view)) } }
4. 及时反注册监听器
-
修复代码:
class MyActivity : AppCompatActivity() { private val receiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { // 处理广播 } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) registerReceiver(receiver, IntentFilter("MY_ACTION")) } override fun onDestroy() { super.onDestroy() unregisterReceiver(receiver) // 反注册 } }
四、总结口诀
“内存泄漏要警惕,Handler 单例和静态,
匿名内部类是大坑,监听反注册别忘记。
LeakCanary 来检测,Profiler 抓堆快分析,
弱引用加及时清,内存优化稳如基!