# Android 常见内存泄漏

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 监听器未反注册

场景BroadcastReceiverEventBusLiveData、自定义监听器等未在 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

场景 :在 lifecycleScopeviewModelScope 外启动协程,且持有 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()
}

避免 :用 lifecycleScopeviewModelScope 等,避免 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 资源未关闭

场景CursorInputStreamOutputStreamSocketOkHttp Response.body 等未关闭。

kotlin 复制代码
// ❌ 错误
val response = call.execute()
val body = response.body?.string()  // 未关闭,连接无法复用

// ✅ 正确
response.use {
    it.body?.use { body ->
        val str = body.string()
    }
}

避免 :用 usetry-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 定时器未取消

场景TimerHandler.postDelayedScheduledExecutorService 等在 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
结构化并发 使用 lifecycleScopeviewModelScope 等,避免 GlobalScope
资源 使用 usetry-finally 确保资源关闭

三、检查清单

检查项 说明
单例/静态变量 是否持有 Activity?改用 WeakReference 或 applicationContext
Handler / Runnable 是否在 onDestroy 中 removeCallbacksAndMessages?
监听器 BroadcastReceiver、EventBus 等是否在 onDestroy 中 unregister?
协程 是否用 lifecycleScope 而非 GlobalScope?
网络请求 是否在 onDestroy 中 cancel?
资源 Cursor、Stream、Response.body 是否关闭?
相关推荐
南城书生2 小时前
Android View 绘制流程
前端
wefly20172 小时前
M3U8 播放调试天花板!m3u8live.cn纯网页无广告,音视频开发效率直接拉满
java·前端·javascript·python·音视频
陈林梓2 小时前
异步组件、动态插槽
前端
喝咖啡的女孩2 小时前
前端巨型列表渲染
前端
兆子龙2 小时前
antd 组件也做了同款效果!深入源码看设计模式在前端组件库的应用
java·前端·架构
前端Hardy2 小时前
Flutter vs React Native vs HarmonyOS:谁更适合下一代跨端?2026 年技术选型终极指南
前端·flutter·react native
前端Hardy2 小时前
Vite 8 来了:彻底抛弃 Rollup 和 esbuild!Rust 重写后,快到 Webpack 连尾灯都看不见
前端·面试·vite
兆子龙2 小时前
lodash 到 lodash-es 多的不仅仅是后缀!深入源码看 ES Module 带来的性能与体积优化
java·前端·架构
heyCHEEMS2 小时前
用 分段渲染 解决小程序长列表卡顿问题
前端·微信小程序