You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

手动依赖容器中App Context为何引发内存泄漏?如何修复?

手动DI单例AppContainer的内存泄漏问题排查与修复

你的代码实现了单例模式的AppContainer用于手动依赖注入,虽然已经使用Application Context,但仍出现内存泄漏,可能的原因及无框架修复方案如下:

代码复现

internal class AppContainer private constructor(context: Context) {

    companion object {
        private var instance: AppContainer? = null

        fun getInstance(context: Context): AppContainer {
            if (instance == null) {
                instance = AppContainer(context.applicationContext)
            }
            return instance!!
        }
    }

    val resourceProvider: ResourceProvider by lazy { provideResourceProvider(context = context.applicationContext) }
    // 其他依赖声明......

}

可能的泄漏原因

Application Context本身是全局生命周期的,不会导致内存泄漏,问题大概率出在以下几点:

  • 依赖对象持有短生命周期引用:ResourceProvider或其他被AppContainer提供的依赖,内部可能持有Activity、Fragment、View或未注销的监听器/订阅等短生命周期对象,而AppContainer作为单例会一直持有这些依赖,导致关联的短生命周期对象无法被GC回收。
  • 依赖初始化时捕获错误上下文:即使你在AppContainer构造里用了applicationContext,如果provideResourceProvider方法内部不小心传入了非Application Context(比如某个调用方传入了Activity Context),也会引发泄漏。
  • 未清理的注册类资源:如果依赖中注册了广播接收器、ContentObserver、RxJava订阅等,但没有在合适时机注销,即使持有Application Context,这些未注销的资源也会导致泄漏。

无框架修复方案

无需借助Dagger等DI框架,通过以下步骤可以修复:

  • 强制校验传入的Context:在getInstance方法中强制要求传入Application Context,避免错误的Context被传入:
    fun getInstance(context: Context): AppContainer {
        // 直接校验是否为Application Context,避免后续处理出错
        require(context is Application) { "必须传入Application Context" }
        if (instance == null) {
            instance = AppContainer(context)
        }
        return instance!!
    }
    
  • 排查所有依赖的实现:
    1. 检查ResourceProvider及其他依赖的代码,确保它们仅持有Application Context,没有引用任何短生命周期对象。
    2. 检查依赖中是否有未注销的监听器、订阅或广播接收器,比如如果ResourceProvider注册了ContentObserver,需要在合适的时机(比如Application的onTerminate)注销。
  • 用弱引用处理短生命周期依赖:如果某些业务场景必须让单例依赖持有短生命周期对象(比如回调接口),改用WeakReference持有:
    class ResourceProvider(
        private val appContext: Context,
        private val callbackRef: WeakReference<ResourceCallback>
    ) {
        fun loadResource() {
            // 使用前先检查引用是否有效
            callbackRef.get()?.onResourceLoaded()
        }
    }
    
  • 定位具体泄漏点:使用LeakCanary工具生成泄漏引用链,精准定位是哪个对象被AppContainer意外持有,从而快速修复问题。

内容的提问来源于stack exchange,提问作者Igor Novikov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 22:54:20