从
JDK1.2
开始,Java
把对象引用分为四种级别,由高到低分别为:强引用、软引用、弱引用和虚引用
强引用(Strong Reference)
// 强引用就是我们经常使用的引用
Object obj = new Object();
- 把一个对象赋给一个引用变量,这个引用变量就是一个强引用
- 只要还有强引用指向一个对象,垃圾收集器就不会回收这个对象
- 显示的设置
obj=null
或超出对象的生命周期,则此对象可以被回收(回收时机视收集策略决定)
软引用(Soft Reference)
实现:java.lang.ref.SoftReference
如果一个对象只具有软引用,内存不足时,垃圾回收器才会回收它(内存充足不会回收)
使用场景:图片缓存或网页缓存
弱引用(Weak Reference)
实现:java.lang.ref.WeakReference
- 当垃圾回收器扫描到只具有弱引用的对象,不管当前内存空间是否足够,都会回收内存。
- 弱引用适合解决某些地方的内存泄漏的问题
ThreadLocal
静态内部类ThreadLocalMap
中的Entry
中的key
就是一个虚引用在静态内部类中,经常会使用虚引用。
虚引用(Phantom Reference)
实现:java.lang.ref.PhantomReference
- 虚引用并不会决定对象的生命周期;
- 若一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收
- 不能单独使用也不能通过它访问对象, 虚引用必须和引用队列 (ReferenceQueue) 联合使用
- 主要作用是跟踪对象被垃圾回收的状态
(提供了一种确保对象被finalize
以后, 做某些事情的机制)get
方法总是返回null
, 因此无法访问对应的引用对象
(意义在于说明一个对象已经进入finalize
阶段, 可以被回收, 用来实现比finalize
机制更灵活的回收操作)
使用场景:跟踪对象被垃圾回收的活动(可以通过虚引用达到回收一些非Java
内的资源)
其他
-
虚引用 vs. 软引用
- 虚引用必需和引用队列
java.lang.ref.ReferenceQueue
联合使用 - 垃圾回收器准备回收一个对象时,如果发现还存在虚引用,会先将虚引用加入到与之关联的引用队列中
- 虚引用必需和引用队列
-
java.util.WeakHashMap
public static void main(String[] args) { // WeakHashMap 的 key 是弱引用 WeakHashMap<String,Integer> map=new WeakHashMap<>(); String key = new String("wekHashMap"); map.put(key,1); System.out.println(map); key=null; System.gc(); // 空了 System.err.println(map); }
-
ReferenceQueue
引用队列- 对象在被回收之前要被放入引用队列保存(
GC
之后被放入队列中) - 【通过开启线程监听该引用队列的变化情况】就可以在对象被回收时采取相应的动作
- 当执行第一次垃圾回收时,软引用或弱引用对象添加到其关联的引用队列中,然后其
finalize
函数才会被执行(如果没复写则不会被执行) - 虚引用,如果被引用对象没有复写
finalize
方法,则是在第一垃圾回收将该类销毁之后,才会将虚拟引用对象添加到引用队列(如果被引用对象复写了 finalize 方法,则是当执行完第二次垃圾回收之后,才会将虚引用对象添加到其关联的引用队列)
一个对象的
finalize()
方法只会被调用一次,而且finalize()
被调用不意味着gc
会立即回收该对象,所以有可能调用finalize()
后,该对象又不需要被回收了,然后到了真正要被回收的时候,因为前面调用过一次,所以不会调用finalize()
,产生问题, 所以,不推荐调用finalize()
方法 - 对象在被回收之前要被放入引用队列保存(
参考资料: