# 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 是否关闭?
相关推荐
QQ1__8115175158 小时前
Spring boot名城小区物业管理系统信息管理系统源码-SpringBoot后端+Vue前端+MySQL【可直接运行】
前端·vue.js·spring boot
钛态8 小时前
前端微前端架构:大项目的救命稻草还是自找麻烦?
前端·vue·react·web
一粒黑子8 小时前
【实战解析】阿里开源 PageAgent:纯前端 GUI Agent,一行JS让网页支持自然语言操控
前端·javascript·开源
独角鲸网络安全实验室8 小时前
2026微信小程序抓包全解析:从实操落地到合规风控,解锁前端调试新范式
前端·微信小程序·小程序·抓包·系统代理绕过·https证书严格校验·进程隔离
紫微AI8 小时前
前端文本测量成了卡死一切创新的最后瓶颈,pretext实现突破了
前端·人工智能·typescript
GISer_Jing8 小时前
AI前端(From豆包)
前端·aigc·ai编程
IT枫斗者8 小时前
前端部署后如何判断“页面是不是最新”?一套可落地的版本检测方案(适配 Vite/Vue/React/任意 SPA)
前端·javascript·vue.js·react.js·架构·bug
测试修炼手册8 小时前
[测试技术] 深入理解 JSON Web Token (JWT)
前端·json
AI老李8 小时前
2026 年 Web 前端开发的 8 个趋势!
前端
里欧跑得慢8 小时前
15. Web可访问性最佳实践:让每个用户都能平等访问
前端·css·flutter·web