一句话说透Android里面的强引用置为null,会不会被回收

132 阅读2分钟

一句话总结:

会!但前提是这个对象没有被其他强引用“拴住”。把强引用设为 null 就像剪断风筝线,但如果有其他线(强引用)还连着,风筝(对象)就飞不走(无法被回收)。


详细解释(现实比喻)

1. 剪断自己的线(置为 null

  • 操作

    var obj: MyObject? = MyObject()  
    obj = null // 剪断自己的线  
    
  • 结果

    • 如果这个对象只被你自己的引用obj)拴着,剪断后会被垃圾回收(GC)收走。
    • 如果还有其他强引用(如静态变量、其他对象持有它),GC 依然不会回收!

2. 其他线还在的情况(内存泄漏)

  • 场景:单例或静态变量持有对象引用。

    object Singleton {  
        var leakedObject: MyObject? = null  
    }  
    
    // 某个地方将对象交给单例  
    val obj = MyObject()  
    Singleton.leakedObject = obj  
    obj = null // 虽然剪断自己的线,但单例的线还连着  
    
  • 结果MyObject 实例无法被回收,导致内存泄漏!


3. 如何确保被回收?

  • 步骤

    1. 剪断所有强引用:确保没有任何变量、集合、静态引用指向该对象。
    2. 避免循环引用:即使对象互相引用,只要外界没有强引用,GC 也会回收(Garbage Collector 能处理循环引用)。
  • 代码示例

    class MyActivity : AppCompatActivity() {  
        private var heavyObject: HeavyObject? = HeavyObject()  
    
        override fun onDestroy() {  
            super.onDestroy()  
            heavyObject = null // 剪断自己的线  
            // 确保其他代码(如单例、静态变量)也释放引用  
        }  
    }  
    

实际开发中的高频坑点

1. Handler 导致的内存泄漏

  • 问题代码

    class MyActivity : AppCompatActivity() {  
        private val handler = Handler(Looper.getMainLooper()) {  
            // 隐式持有 Activity 的引用  
            true  
        }  
    
        override fun onDestroy() {  
            super.onDestroy()  
            // 忘记调用 handler.removeCallbacksAndMessages(null)  
        }  
    }  
    
  • 解决:在 onDestroy 中移除所有回调,并置 handler 为 null


2. 静态变量持有 Context/Activity

  • 问题代码

    companion object {  
        var staticActivity: Activity? = null  
    }  
    
    // 某个地方赋值  
    staticActivity = this  
    
  • 解决:在 onDestroy 中置 staticActivity = null,或改用 WeakReference


总结口诀

“强引用置 null 可回收,前提是再无他人留,
若有静态单例栓,内存泄漏在心头。
Handler 监听要反注,静态变量用弱引,
工具检测加实践,内存优化不用愁!”

用工具(如 Android Studio 的 Memory Profiler 或 LeakCanary)验证对象是否真被回收!