Java中存在四種引用,分別為強(qiáng)引用(Strong Reference)
身诺、軟引用(Soft Refefence)
蜜托、弱引用(Weak Refefence)
和虛引用(Phantom Refefence)
,這四種引用的強(qiáng)度依次減弱霉赡。
一橄务、強(qiáng)引用
強(qiáng)引用就是指在程序代碼中普遍存在的,類似Object obj = new Object()
這類的引用穴亏,只要強(qiáng)引用還存在蜂挪,垃圾收集器永遠(yuǎn)不會(huì)回收掉被引用的對(duì)象。如果沒有足夠的內(nèi)存嗓化,就會(huì)拋出內(nèi)存溢出異常棠涮。
public class StrongReferenceTest {
private static final int MEGA_BYTE = 1024 * 1024;
/**
* -Xms10M -Xmx10M -Xmn5M
*/
public static void main(String[] args) {
byte[] tenMegaByte1 = new byte[MEGA_BYTE * 2];
byte[] tenMegaByte2 = new byte[MEGA_BYTE * 2];
byte[] tenMegaByte3 = new byte[MEGA_BYTE * 2];
byte[] tenMegaByte4 = new byte[MEGA_BYTE * 2];
byte[] tenMegaByte5 = new byte[MEGA_BYTE * 2];
}
}
如上代碼所示,最大堆空間為10M
刺覆,然后創(chuàng)建五個(gè)每個(gè)大小都為2M
的大對(duì)象严肪,GC回收的時(shí)候發(fā)現(xiàn)這五個(gè)對(duì)象都是強(qiáng)引用,沒法回收內(nèi)存谦屑,拋出OutOfMemoryError
驳糯。運(yùn)行結(jié)果如下:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at top.liaohuaida.reference.StrongReferenceTest.main(StrongReferenceTest.java:17)
二、軟引用
Java中提供了SoftReference
類來實(shí)現(xiàn)軟引用氢橙。軟引用是用來描述一些還有用但并非必需的對(duì)象酝枢。對(duì)于軟引用的關(guān)聯(lián)著的對(duì)象,在系統(tǒng)將要發(fā)生內(nèi)存溢出異常之前悍手,將會(huì)把這些對(duì)象列進(jìn)回收范圍之中進(jìn)行第二次回收帘睦。如果這次回收還沒有足夠的內(nèi)存袍患,才會(huì)拋出內(nèi)存溢出異常。
public class SoftReferenceTest {
private static final int MEGA_BYTE = 1024 * 1024;
/**
* -Xms10M -Xmx10M -Xmn5M
*/
public static void main(String[] args) {
SoftReference<byte[]> softReference1 = new SoftReference<byte[]>(new byte[MEGA_BYTE * 2]);
System.gc();
System.out.println("第一次GC后SoftReference的值:" + softReference1.get());
SoftReference<byte[]> softReference2 = new SoftReference<byte[]>(new byte[MEGA_BYTE * 2]);
System.gc();
System.out.println("第二次GC后SoftReference的值:" + softReference1.get());
SoftReference<byte[]> softReference3 = new SoftReference<byte[]>(new byte[MEGA_BYTE * 2]);
System.gc();
System.out.println("第三次GC后SoftReference的值:" + softReference1.get());
SoftReference<byte[]> softReference4 = new SoftReference<byte[]>(new byte[MEGA_BYTE * 2]);
System.gc();
System.out.println("第四次GC后SoftReference的值:" + softReference1.get());
System.gc();
SoftReference<byte[]> softReference5 = new SoftReference<byte[]>(new byte[MEGA_BYTE * 2]);
System.out.println("第五次GC后SoftReference的值:" + softReference1.get());
}
}
如上代碼所示官脓,每次創(chuàng)建一個(gè)2M
的對(duì)象之后协怒,就顯示調(diào)用一次System.gc()
來回收內(nèi)存,結(jié)果如下所示卑笨,前四次回收并沒有回收掉softReference1
關(guān)聯(lián)對(duì)象的內(nèi)存孕暇。但是第五次回收的時(shí)候,內(nèi)存不足赤兴,將要發(fā)生內(nèi)存溢出妖滔,此時(shí)softReference1
關(guān)聯(lián)對(duì)象的內(nèi)存被回收,其實(shí)其他SoftReference
關(guān)聯(lián)對(duì)象的內(nèi)存也都被回收掉了桶良。
第一次GC后SoftReference的值:[B@6d13722b
第二次GC后SoftReference的值:[B@6d13722b
第三次GC后SoftReference的值:[B@6d13722b
第四次GC后SoftReference的值:[B@6d13722b
第五次GC后SoftReference的值:null
三座舍、弱引用
Java提供了WeakReference
類來實(shí)現(xiàn)弱引用。弱引用也是用來描述非必要對(duì)象的陨帆,但是它的強(qiáng)度比軟引用更弱一些曲秉,被弱引用關(guān)聯(lián)的對(duì)象只能生存到下一次垃圾收集發(fā)生之前。當(dāng)垃圾收集器工作時(shí)疲牵,無論當(dāng)前內(nèi)存是否足夠承二,都會(huì)回收掉只被弱引用關(guān)聯(lián)的對(duì)象。
public class WeakReferenceTest {
private static final int MEGA_BYTE = 1024 * 1024;
/**
* -Xms10M -Xmx10M -Xmn5M
*/
public static void main(String[] args) {
WeakReference<byte[]> weakReference1 = new WeakReference<byte[]>(new byte[MEGA_BYTE * 2]);
System.out.println("第一次GC前weakReference1的值:" + weakReference1.get());
System.gc();
System.out.println("第一次GC后weakReference1的值:" + weakReference1.get());
WeakReference<byte[]> weakReference2 = new WeakReference<byte[]>(new byte[MEGA_BYTE * 2]);
System.out.println("第二次GC前weakReference2的值:" + weakReference2.get());
System.gc();
System.out.println("第二次GC后weakReference2的值:" + weakReference2.get());
// WeakReference<byte[]> weakReference3 = new WeakReference<byte[]>(new byte[MEGA_BYTE * 2]);
// System.gc();
// System.out.println("第三次GC后weakReference3的值:" + weakReference3.get());
// WeakReference<byte[]> weakReference4 = new WeakReference<byte[]>(new byte[MEGA_BYTE * 2]);
// System.gc();
// System.out.println("第四次GC后weakReference4的值:" + weakReference4.get());
// System.gc();
// WeakReference<byte[]> weakReference5 = new WeakReference<byte[]>(new byte[MEGA_BYTE * 2]);
// System.out.println("第五次GC后weakReference5的值:" + weakReference5.get());
}
}
如上代碼所示纲爸,每次創(chuàng)建一個(gè)2M
的對(duì)象之后亥鸠,就顯示調(diào)用一次System.gc()
來回收內(nèi)存,結(jié)果如下所示识啦,每次回收內(nèi)存都會(huì)回收掉WeakReference
關(guān)聯(lián)對(duì)象的內(nèi)存负蚊,而不管內(nèi)存是否充足。注釋掉的部分結(jié)果也是相同的颓哮。
第一次GC前weakReference1的值:[B@21a437b6
第一次GC后weakReference1的值:null
第二次GC前weakReference2的值:[B@8939ec3
第二次GC后weakReference2的值:null
四家妆、虛引用
Java提供PhantomReference
類來實(shí)現(xiàn)虛引用。虛引用也被稱為幽靈引用
或者幻影引用
冕茅,它是一種最弱的引用關(guān)系揩徊。一個(gè)對(duì)象是否有虛引用的存在,完全不會(huì)對(duì)其生存時(shí)間構(gòu)成影響嵌赠,也無法通過虛引用來取得一個(gè)對(duì)象實(shí)例塑荒。在一個(gè)對(duì)象設(shè)置虛引用關(guān)聯(lián)的唯一目的就是能在這個(gè)對(duì)象被垃圾收集回收時(shí)收到一個(gè)系統(tǒng)通知。