Android 常见内存泄漏与避免
一、常见泄漏场景与处理
1.1 Activity / Fragment 被静态或长生命周期对象持有
场景:单例、静态变量、Application 等持有 Activity/Fragment 引用。
kotlin
// ❌ 错误
object Singleton {
var activity: Activity? = null // 静态持有 Activity
}
// ✅ 正确
object Singleton {
private var activityRef: WeakReference<Activity>? = null
fun setActivity(activity: Activity) {
activityRef = WeakReference(activity)
}
}
避免 :用 WeakReference 或确保在 onDestroy 中置空引用。
1.2 非静态内部类 / 匿名内部类持有外部类
场景:Handler、Runnable、Thread、AsyncTask 等持有 Activity。
kotlin
// ❌ 错误:匿名 Runnable 持有 Activity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Handler(Looper.getMainLooper()).postDelayed({
findViewById<View>(R.id.text).text = "done" // 持有 this(MainActivity)
}, 10000)
}
}
// ✅ 正确:静态内部类 + 弱引用,或在 onDestroy 中 removeCallbacks
class MainActivity : AppCompatActivity() {
private val handler = Handler(Looper.getMainLooper())
override fun onDestroy() {
handler.removeCallbacksAndMessages(null) // 移除所有回调,避免泄漏
super.onDestroy()
}
}
避免 :用静态内部类 + WeakReference,或在 onDestroy 中移除回调和消息。
1.3 监听器未反注册
场景 :BroadcastReceiver、EventBus、LiveData、自定义监听器等未在 onDestroy 中注销。
kotlin
// ❌ 错误
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
LocalBroadcastManager.getInstance(this).registerReceiver(receiver, filter)
EventBus.getDefault().register(this)
}
}
// ✅ 正确
override fun onDestroy() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver)
EventBus.getDefault().unregister(this)
super.onDestroy()
}
避免 :在 onDestroy 中对称注销所有注册的监听器。
1.4 协程持有 Activity 或 Context
场景 :在 lifecycleScope 或 viewModelScope 外启动协程,且持有 Activity 引用。
kotlin
// ❌ 错误:GlobalScope 协程持有 Activity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
GlobalScope.launch {
delay(5000)
runOnUiThread { updateUI() } // 持有 this(MainActivity)
}
}
}
// ✅ 正确:使用 lifecycleScope,自动取消
lifecycleScope.launch {
delay(5000)
updateUI()
}
避免 :用 lifecycleScope、viewModelScope 等,避免 GlobalScope 和长时间持有 Activity。
1.5 单例持有 Context
场景:单例、工具类持有 Activity 或 Context。
kotlin
// ❌ 错误
object ImageLoader {
private var context: Context? = null // 若传入 Activity,会泄漏
fun init(ctx: Context) { context = ctx }
}
// ✅ 正确:使用 ApplicationContext
fun init(ctx: Context) {
context = ctx.applicationContext
}
避免 :用 applicationContext,不要用 Activity 作为 Context 传给单例。
1.6 View 持有 Activity
场景:自定义 View 或 Adapter 持有 Activity 引用。
kotlin
// ❌ 错误
class MyAdapter(private val activity: Activity) : RecyclerView.Adapter<...>()
// ✅ 正确:传 Context 或 Fragment
class MyAdapter(private val context: Context) : RecyclerView.Adapter<...>()
避免 :尽量传 Context 或 Fragment,避免直接持有 Activity。
1.7 资源未关闭
场景 :Cursor、InputStream、OutputStream、Socket、OkHttp Response.body 等未关闭。
kotlin
// ❌ 错误
val response = call.execute()
val body = response.body?.string() // 未关闭,连接无法复用
// ✅ 正确
response.use {
it.body?.use { body ->
val str = body.string()
}
}
避免 :用 use 或 try-finally 确保资源关闭。
1.8 第三方库回调持有 Activity
场景:Glide、Retrofit、OkHttp 等回调在 Activity 销毁后仍可能被调用。
kotlin
// ❌ 错误
call.enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
// 若 Activity 已销毁,可能仍持有 Activity
textView.text = response.body().toString()
}
})
// ✅ 正确:在 onDestroy 中 cancel
private var call: Call? = null
override fun onDestroy() {
call?.cancel()
super.onDestroy()
}
避免 :在 onDestroy 中取消请求,避免回调持有 Activity。
1.9 定时器未取消
场景 :Timer、Handler.postDelayed、ScheduledExecutorService 等在 Activity 销毁后仍运行。
kotlin
// ✅ 正确
private val handler = Handler(Looper.getMainLooper())
private val runnable = Runnable { /* ... */ }
override fun onDestroy() {
handler.removeCallbacks(runnable)
super.onDestroy()
}
避免 :在 onDestroy 中移除回调和消息。
1.10 闭包 / Lambda 持有外部引用
场景 :Kotlin 中 lambda 捕获了 this 或 Activity。
kotlin
// ❌ 错误
view.setOnClickListener {
// 持有 Activity
startActivity(Intent(this@MainActivity, OtherActivity::class.java))
}
// 若 lambda 被传给会长期持有的对象,需注意
避免:注意 lambda 捕获的引用,避免被长生命周期对象持有。
二、排查与规避建议
| 手段 | 说明 |
|---|---|
| LeakCanary | 在 debug 中接入,自动检测 Activity 等泄漏 |
| 弱引用 | 单例、静态变量引用 Activity 时用 WeakReference |
| 生命周期 | 在 onDestroy 中置空引用、取消注册、取消任务 |
| ApplicationContext | 单例、工具类使用 applicationContext |
| 结构化并发 | 使用 lifecycleScope、viewModelScope 等,避免 GlobalScope |
| 资源 | 使用 use 或 try-finally 确保资源关闭 |
三、检查清单
| 检查项 | 说明 |
|---|---|
| 单例/静态变量 | 是否持有 Activity?改用 WeakReference 或 applicationContext |
| Handler / Runnable | 是否在 onDestroy 中 removeCallbacksAndMessages? |
| 监听器 | BroadcastReceiver、EventBus 等是否在 onDestroy 中 unregister? |
| 协程 | 是否用 lifecycleScope 而非 GlobalScope? |
| 网络请求 | 是否在 onDestroy 中 cancel? |
| 资源 | Cursor、Stream、Response.body 是否关闭? |