Java引用类型
Java中有四种引用类型。其中SoftReference、WeakReference、PhantomReference构造时都可以指定ReferenceQueue,当目标对象 (Referent) 被回收时,Reference会被添加到队列中。
中文
英文
取得目标对象 (Referent) 方式
垃圾回收条件
ReferenceQueue构造参数
强引用
StrongReference
直接调用
不回收
-
软引用
SoftReference
get方法
gc且内存不足时回收
可选参数
弱引用
WeakReference
get方法
gc时回收
可选参数
虚引用
PhantomReference
无法取得,get方法始终返回null
gc时回收
必传参数
使用的坑
注意软引用 / 弱引用的一个坑:
1 | String s = "string"; |
应用
SoftReference、WeakReference都可以用作缓存,例如Glide图片库使用了WeakReference缓存。
WeakReference还可以用于监控内存,例如LeakCanary。
PhantomReferences和WeakReference类似,区别是PhantomReferences不能获取到目标对象。
PhantomReferences的两种作用:
- 监控对象是否已回收,以便实现内存敏感的需求,例如可以等待大对象回收后再创建下一个。
- 代替finalize方法,自行执行回收操作,减小gc压力。
例:LeakCanary在Android中监控内存泄露
LeakCanary可用于检测Android内存泄露,内存追踪使用了WeakReference。
基于LeakCanary 1.5.4源码,流程描述如下:
ActivityRefWatcher
:Activity.onDestroy()时,添加Activity对象到RefWatcher
监控列表中(创建一个虚引用)。AndroidWatchExecutor
:延时5s。RefWatcher
:通过ReferenceQueue,判断对象是否已回收。GcTrigger
:如果没有回收,触发gc。RefWatcher
:判断对象是否已回收。AndroidHeapDumper
:如果没有回收,可能有内存泄露。调用Android提供的Debug.dumpHprofData()
,生成Heap Dump(堆转储文件)。HeapAnalyzerService
:调用haha模块分析内存泄露。
参考: LeakCanary 源码解析
例:PhantomReferences代替finalize方法执行回收操作
Java对象在被gc回收时,finalize方法会被调用。如果在finalize中执行了复杂的任务,会增加gc压力,因此可以借助PhantomReferences自行处理。
代码来自 Phantom References in Java
1 | public class LargeObjectFinalizer extends PhantomReference<Object> { |
1 | ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>(); |