強(qiáng)引用
特點(diǎn):我們平常典型編碼Object obj = new Object()中的obj就是強(qiáng)引用。通過(guò)關(guān)鍵字new創(chuàng)建的對(duì)象所關(guān)聯(lián)的引用就是強(qiáng)引用。 當(dāng)JVM內(nèi)存空間不足,JVM寧愿拋出OutOfMemoryError運(yùn)行時(shí)錯(cuò)誤(OOM),使程序異常終止,也不會(huì)靠隨意回收具有強(qiáng)引用的“存活”對(duì)象來(lái)解決內(nèi)存不足的問(wèn)題。對(duì)于一個(gè)普通的對(duì)象,如果沒(méi)有其他的引用關(guān)系,只要超過(guò)了引用的作用域或者顯式地將相應(yīng)(強(qiáng))引用賦值為 null,就是可以被垃圾收集的了,具體回收時(shí)機(jī)還是要看垃圾收集策略。
軟引用
特點(diǎn):軟引用通過(guò)SoftReference類實(shí)現(xiàn)。 軟引用的生命周期比強(qiáng)引用短一些。只有當(dāng) JVM 認(rèn)為內(nèi)存不足時(shí),才會(huì)去試圖回收軟引用指向的對(duì)象:即JVM 會(huì)確保在拋出 OutOfMemoryError 之前,清理軟引用指向的對(duì)象。軟引用可以和一個(gè)引用隊(duì)列(ReferenceQueue)聯(lián)合使用,如果軟引用所引用的對(duì)象被垃圾回收器回收,Java虛擬機(jī)就會(huì)把這個(gè)軟引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。后續(xù),我們可以調(diào)用ReferenceQueue的poll()方法來(lái)檢查是否有它所關(guān)心的對(duì)象被回收。如果隊(duì)列為空,將返回一個(gè)null,否則該方法返回隊(duì)列中前面的一個(gè)Reference對(duì)象。
應(yīng)用場(chǎng)景:軟引用通常用來(lái)實(shí)現(xiàn)內(nèi)存敏感的緩存。如果還有空閑內(nèi)存,就可以暫時(shí)保留緩存,當(dāng)內(nèi)存不足時(shí)清理掉,這樣就保證了使用緩存的同時(shí),不會(huì)耗盡內(nèi)存。
/**
* java -Xms10m -Xmx10m SoftReferenceTest
*/
public class SoftReferenceQueueTest {
static class HeapObject {
byte[] bs = new byte[1024 * 1024];
}
public static void main(String[] args) {
ReferenceQueue<HeapObject> queue=new ReferenceQueue<>();
SoftReference<HeapObject> softReference = new SoftReference<>(new HeapObject(),queue);
List<HeapObject> list = new ArrayList<>();
while (true) {
if (softReference.get() != null) {
list.add(new HeapObject());
System.out.println("list.add");
} else {
System.out.println("---------軟引用已被回收---------");
break;
}
System.gc();
}
Reference<? extends HeapObject> pollRef = queue.poll();
while (pollRef != null) {
System.out.println(pollRef);
System.out.println(pollRef.get());
pollRef = queue.poll();
}
}
}
輸出:
list.add
list.add
list.add
list.add
list.add
list.add
list.add
---------軟引用已被回收---------
java.lang.ref.SoftReference@7d417077
null
如果去掉list.add(new HeapObject());則軟引用一直不會(huì)被回收
弱引用
弱引用通過(guò)WeakReference類實(shí)現(xiàn)。 弱引用的生命周期比軟引用短。在垃圾回收器線程掃描它所管轄的內(nèi)存區(qū)域的過(guò)程中,一旦發(fā)現(xiàn)了具有弱引用的對(duì)象,不管當(dāng)前內(nèi)存空間足夠與否,都會(huì)回收它的內(nèi)存。由于垃圾回收器是一個(gè)優(yōu)先級(jí)很低的線程,因此不一定會(huì)很快回收弱引用的對(duì)象。弱引用可以和一個(gè)引用隊(duì)列(ReferenceQueue)聯(lián)合使用,如果弱引用所引用的對(duì)象被垃圾回收,Java虛擬機(jī)就會(huì)把這個(gè)弱引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。
應(yīng)用場(chǎng)景:弱應(yīng)用同樣可用于內(nèi)存敏感的緩存。
public class WeakReferenceTest {
static class HeapObject {
byte[] bs = new byte[1024 * 1024];
}
public static void main(String[] args) throws InterruptedException {
ReferenceQueue<HeapObject> queue=new ReferenceQueue<>();
WeakReference<HeapObject> weakReference=new WeakReference<>(new HeapObject(), queue);
List<HeapObject> list = new ArrayList<>();
while (true) {
if (weakReference.get() != null) {
System.gc();
System.out.println("list.add");
} else {
System.out.println("---------弱引用已被回收---------");
break;
}
}
Reference<? extends HeapObject> pollRef = queue.poll();
while (pollRef != null) {
System.out.println(pollRef);
System.out.println(pollRef.get());
pollRef = queue.poll();
}
}
}
輸出:
list.add
---------弱引用已被回收---------
java.lang.ref.WeakReference@7440e464
null
如果是弱引用,則不需要把jvm內(nèi)存呈報(bào)也會(huì)回收弱引用。
虛引用
特點(diǎn):虛引用也叫幻象引用,通過(guò)PhantomReference類來(lái)實(shí)現(xiàn)。無(wú)法通過(guò)虛引用訪問(wèn)對(duì)象的任何屬性或函數(shù)?;孟笠脙H僅是提供了一種確保對(duì)象被 finalize 以后,做某些事情的機(jī)制。如果一個(gè)對(duì)象僅持有虛引用,那么它就和沒(méi)有任何引用一樣,在任何時(shí)候都可能被垃圾回收器回收。虛引用必須和引用隊(duì)列 (ReferenceQueue)聯(lián)合使用。當(dāng)垃圾回收器準(zhǔn)備回收一個(gè)對(duì)象時(shí),如果發(fā)現(xiàn)它還有虛引用,就會(huì)在回收對(duì)象的內(nèi)存之前,把這個(gè)虛引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。
ReferenceQueue queue = new ReferenceQueue ();
PhantomReference pr = new PhantomReference (object, queue);
程序可以通過(guò)判斷引用隊(duì)列中是否已經(jīng)加入了虛引用,來(lái)了解被引用的對(duì)象是否將要被垃圾回收。如果程序發(fā)現(xiàn)某個(gè)虛引用已經(jīng)被加入到引用隊(duì)列,那么就可以在所引用的對(duì)象的內(nèi)存被回收之前采取一些程序行動(dòng)。
應(yīng)用場(chǎng)景:可用來(lái)跟蹤對(duì)象被垃圾回收器回收的活動(dòng),當(dāng)一個(gè)虛引用關(guān)聯(lián)的對(duì)象被垃圾收集器回收之前會(huì)收到一條系統(tǒng)通知。
public class PhantomReferenceTest {
static class TestObject {
}
public static void main(String[] args) throws InterruptedException {
ReferenceQueue<TestObject> queue = new ReferenceQueue<>();
PhantomReference<TestObject> phantomReference = new PhantomReference<>(new TestObject(), queue);
System.out.println(phantomReference.get() == null);//true
Reference reference = queue.poll();
System.out.println(reference);
while (reference==null){
reference = queue.poll();
System.gc();
System.out.println(reference);
}
System.out.println("last poll:"+queue.poll());
}
}
輸出:
true
null
null
java.lang.ref.PhantomReference@7440e464
last poll:null
參考:https://time.geekbang.org/column/article/6970
示例參考:https://blog.csdn.net/u011179993/article/details/54564380