强引用
强引用(strong reference)是使用最普遍的引用,如果一个对象具有强引用,那垃圾回收器绝不会回收它,例如Object obj = new Object();
,即使当内存空间不足时,JVM宁愿抛出OOM,也不会回收具有强引用的对象来解决内存不足的问题。
我们可以显示的设置对象为null,或者跳出对象的生命周期范围,让垃圾收集器将其判定为不存在引用,是个可以被回收的对象,例如obj = null;
全局对象:手动的将对象赋值为null,最典型的全局对象设置为null的就是在ArrayList的clear()方法中,对于类中的全局变量elementData
来说,仅仅的将其置为null是不可行的,因为数组中的对象还是会继续引用的,所以此时需要将数组中每个位置的对象全部置为null,也就是将所有的对象的引用都释放掉,这样才会被GC回收。
1 | /** |
局部变量:一般情况下,一个对象保存在堆中,对象的引用保存在Java栈中,由于栈是线程私有的,所以当线程结束时,Java栈被自动回收,这时堆中对象的引用数-1,直到引用数变为0后,可以被GC回收。例如:
1 | public void method() { |
我们通过new创建的对象一般都是强引用
弱引用
弱引用(weak reference)是可以被GC强制回收的,当垃圾收集器发现一个存活的弱可达对象时,就会将其放入响应的ReferenceQueue中,之后可能会遍历这个ReferenceQueue并执行响应的清理,弱可达对象是指该对象的引用只剩下弱引用。
我们可以通过弱引用的get()方法给对象赋值给新的强引用,在回收前,GC会再次判断该对象是否可以安全回收。所以,弱引用的对象的回收过程可以横跨多个GC周期,在Java中可以使用WeakReference
类创建一个弱引用对象。例如:
1 | public static void main(String[] args) throws Exception { |
分析
仅开启①
弱引用对象尚未被回收
仅开启②
仅开启③
开启①②
哇啊哦~对象被回收了,这是因为我们先将对象的弱引用断开,然后又手动进行了一次gc,把对象给回收了
开启②③
开启①②③
软引用
软引用(Soft Reference)是比弱引用更难被垃圾回收器回收的对象,什么时候回收软引用完全由JVM自己决定,一般只会在即将OOM时才会回收软引用,算是JVM内存管理最后的倔强。这就意味着可能会有非常频繁的Full GC,STW时间也变长,因为老年代中的存活对象多了。
1 | public static void main(String[] args) throws Exception { |
虚引用
虚引用和弱引用、软引用不同,它并不影响对象的生命周期,使用java.lang.ref.PhantomReference
类表示,和弱引用、软引用不同的是,虚引用必须和引用队列关联使用,当GC准备回收一个对象时,如果发现它还有虚引用,就会把这个虚引用放进与之关联的引用队列中。
为了防止可回收对象的残留,虚引用对象不应该被获取,PhantomReference的get()方法始终返回null,虚引用不会被GC自动清除,因为它们被存放到队列中,通过虚引用可达的对象会继续留在内存中,直到调用此引用的clear()方法,或者引用自身变为不可达。
也就是说我们如果不手动调用clear()方法来清除虚引用,则非常可能造成OOM而导致JVM宕机。
1 | public static void main(String[] args) throws Exception { |
可以使用JVM参数-XX:+PrintReferenceGC
查看各类引用对GC的影响