一、強引用
強引用比較好理解,我們編程中絕大部分對象都是強引用,在GC過程中,如果存在強引用對象,即便發(fā)生OOM,也不會被回收
Object m = new Object();
二、軟引用
在堆內(nèi)存不足時,jvm的GC會回收軟引用對象
public class SoftReferenceTest {
public static void main(String[] args) {
SoftReference<byte[]> m = new SoftReference<>(new byte[1024 * 1024 * 10]);
System.out.println(m.get());
System.gc();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(m.get());
byte[] b = new byte[1024 * 1024 * 15];
System.out.println(m.get());
}
}
上述代碼在內(nèi)存中的引用關(guān)系如下圖所示
假如我們指定-Xmx20M,然后運行
[B@2503dbd3
[B@2503dbd3
null
從運行結(jié)果可以看出,第一次和第二次輸入對象不為空,即便中間發(fā)生了一次gc,第二次依然不為空,是因為內(nèi)存足夠,所以不會被回收,但是當?shù)谌蝞ew一個15M的對象時,總空間15+10=25M,超出堆內(nèi)存總大小(20M),這時jvm會回收調(diào)軟引用對象。
軟引用的使用場景:緩存(比如緩存一些圖片文件)
三、弱引用
把上面代碼稍作修改,將軟引用改為弱引用,其他保持不變
public class WeakReferenceTest {
public static void main(String[] args) {
WeakReference<byte[]> m = new WeakReference<>(new byte[1024 * 1024 * 10]);
System.out.println(m.get());
System.gc();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(m.get());
byte[] b = new byte[1024 * 1024 * 15];
System.out.println(m.get());
}
}
運行結(jié)果
[B@2503dbd3
null
null
從運行結(jié)果可以看出,第二次輸出時,即便內(nèi)存足夠,依然會被回收。
結(jié)論:垃圾回收器會直接回收弱引用對象,和軟引用的區(qū)別就是不管內(nèi)存是否充裕都會被回收。
ThreadLocal就是用到了弱引用技術(shù),關(guān)于ThreadLocal可以參見另一篇博文
ThreadLocal
四、虛引用
public class PhantomReferenceTest {
private static final List<Object> LIST = new LinkedList<>();
private static final ReferenceQueue<M> QUEUE = new ReferenceQueue<>();
public static void main(String[] args) {
PhantomReference<M> pr = new PhantomReference<>(new M(), QUEUE);
//虛引用輸出為空
System.out.println(pr.get());
}
}
java官方的解釋:
Phantom reference objects, which are enqueued after the collector determines that their referents may otherwise be reclaimed. Phantom references are most often used for scheduling pre-mortem cleanup actions in a more flexible way than is possible with the Java finalization mechanism.
虛引用指向的對象有可能會被重新訪問到,常用于對象死亡后的清理操作。
在NIO場景中,堆內(nèi)存中的對象有可能會訪問堆外內(nèi)存的對象,當堆內(nèi)存被GC回收時,堆外內(nèi)存也應(yīng)該釋放,JVM是怎么知道堆外內(nèi)存是否可回收呢,所以java提供了一種鉤子機制,這種機制就是虛引用。