Android 对象引用机制详解
在 Android 开发中,Java 虚拟机通过不同的引用类型来管理对象生命周期与垃圾回收行为。掌握这些引用机制,能够有效优化内存使用并规避泄漏风险。
一、强引用(StrongReference)
强引用是程序中最普遍的引用形式。只要对象存在强引用,垃圾回收器绝不会回收该对象,哪怕系统内存紧张。
public class DemoActivity extends AppCompatActivity {
// 危险:静态成员长期持有 Activity 实例
private static DemoActivity retainedInstance;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
retainedInstance = this; // 造成内存泄漏
}
}
上述代码中,retainedInstance 作为静态变量生命周期贯穿应用始终,导致关联的 Activity 无法被释放。
二、软引用(SoftReference)
软引用指向的对象在内存充裕时得以保留,当堆空间即将耗尽时会被回收。适合构建弹性缓存策略。
public class ImageMemoryCache {
private final Map<String, SoftReference<Bitmap>> cachePool = new HashMap<>();
public void put(String identifier, Bitmap image) {
cachePool.put(identifier, new SoftReference<>(image));
}
public Bitmap fetch(String identifier) {
SoftReference<Bitmap> wrapper = cachePool.get(identifier);
if (wrapper == null) return null;
Bitmap result = wrapper.get();
if (result == null) {
cachePool.remove(identifier); // 清理失效引用
}
return result;
}
}
三、弱引用(WeakReference)
弱引用不阻碍垃圾回收,一旦 GC 执行,关联对象即被回收。常用于打破循环引用或防止回调泄漏。
public class SafeHandler extends Handler {
private final WeakReference<Activity> hostRef;
public SafeHandler(Activity host) {
this.hostRef = new WeakReference<>(host);
}
@Override
public void handleMessage(Message msg) {
Activity host = hostRef.get();
if (host == null || host.isFinishing()) {
return; // 宿主已销毁,放弃操作
}
// 执行 UI 更新逻辑
}
}
四、虚引用(PhantomReference)
虚引用无法通过 get() 获取对象实例,仅用于追踪对象被回收的时机,必须配合 ReferenceQueue 使用。
public class ResourceTracker {
private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
public PhantomReference<Object> monitor(Object target) {
return new PhantomReference<>(target, queue);
}
public void processReclaimed() {
Reference<?> ref;
while ((ref = queue.poll()) != null) {
// 对象已 finalize,执行善后清理
performCleanup(ref);
}
}
}
引用特性对比
| 引用类别 | 回收条件 | 典型应用场景 |
|---|---|---|
| 强引用 | 引用链断开或作用域终结 | 常规对象持有 |
| 软引用 | 内存不足触发 OOM 前 | 图片缓存、数据暂存 |
| 弱引用 | 每次 GC 执行时 | Handler、监听器防泄漏 |
| 虚引用 | 对象 finalize 之后 | 堆外资源回收通知 |
实践要点
- 优先使用
WeakHashMap实现自动清理的键值缓存 - 避免在静态上下文中持有 Context 强引用
- 虚引用的监控线程需妥善管理,防止成为性能瓶颈
- Android 8.0 起部分引用 API 有所调整,需关注版本兼容性