一句话总结:
会!但前提是这个对象没有被其他强引用“拴住”。把强引用设为 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. 如何确保被回收?
-
步骤:
- 剪断所有强引用:确保没有任何变量、集合、静态引用指向该对象。
- 避免循环引用:即使对象互相引用,只要外界没有强引用,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)验证对象是否真被回收!