介紹
在Java中操作對象都需要用到引用類似于C++中的指針,可以說在Java語言中無時無刻不在和引用打交道在Java 1.2版本中就加入了四種不同級別的引用供開發(fā)人員使用逆济,分別是強應(yīng)用 軟引用 弱引用 幽靈引用 強度從高到低。
引用級別作用
引用級別的高低起到了JVM在內(nèi)存不足的時候娇掏,進行GC操作是否需要回收這個對象的作用蛮浑。
強引用
強引用在開發(fā)中是使用最為普遍的引用級別,當(dāng)使用new obj關(guān)鍵字創(chuàng)建了對象后鄙信,這個對象就屬于強引用了。 如果JVM在內(nèi)存不足情況下進行垃圾回收操作時遇到了強引用的對象忿晕,JVM就算拋出OutOfMemoryError錯誤導(dǎo)致程序終止装诡,也不會去回收一個具有強引用級別的對象來解決內(nèi)存不足的問題。
創(chuàng)建一個DataTest類覆蓋object的finalize方法践盼,finalize是當(dāng)GC回收當(dāng)前對象的時候會調(diào)用鸦采,但是不一定每次都會調(diào)用。
class DataTest extends Object {
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("--------obj is gc--------");
}
}
模擬大量消耗內(nèi)存
public static void drainMemory() {
String[] array = new String[1024 * 10];
for(int i = 0; i < 1024 * 10; i++) {
for(int j = 'a'; j <= 'z'; j++) {
array[i] += (char)j;
}
}
}
測試
@Test
public void onRTre() {
DataTest dataTest = new DataTest();
drainMemory();
}
運行結(jié)果: 消耗了大量內(nèi)存也沒有回收對象
無任何輸入
把引用賦為null
@Test
public void onRTre() {
DataTest dataTest = new DataTest();
dataTest=null;
drainMemory();
}
運行結(jié)果: 隱式GC消耗大量內(nèi)存導(dǎo)致內(nèi)存不足咕幻,回收了無引用對象
--------obj is gc--------
@Test
public void onRTre() {
DataTest dataTest = new DataTest();
dataTest=null;
System.gc();
}
運行結(jié)果: 顯式GC操作渔伯,雖然內(nèi)存足夠也回收了無引用對象。
--------obj is gc--------
軟引用
具有軟引用的對象肄程,當(dāng)JVM內(nèi)存足夠的情況下是不會回收它锣吼,當(dāng)內(nèi)存不足情況下GC操作JVM就會回收具有軟引用的對象选浑,軟引用可以用來做那些需要緩存的操作,當(dāng)JVM內(nèi)存不足的時候這些緩存可以被GC掉玄叠。
@Test
public void onRTre() {
SoftReference reference = new SoftReference(new DataTest());
drainMemory();
}
運行結(jié)果:運行五次古徒,有一次輸出。說明GC遇到軟引用的時候是由JVM運行情況決定读恃,是否需要回收軟引用對象隧膘,內(nèi)存不足有可能會回收也有可能不會被回收。如果當(dāng)前對象被GC對象就不能被使用了寺惫,否則可以繼續(xù)使用疹吃。
--------obj is gc--------
弱引用
弱引用級別的對象,只有JVM進行GC操作的時候遇到是弱引用級別西雀,不管內(nèi)存是否足夠都會把對象GC掉萨驶。不過由于GC是在一個級別很低的線程,所以不一定能馬上發(fā)現(xiàn)那些弱引用的對象艇肴。
@Test
public void onRTre() {
WeakReference reference = new WeakReference(new DataTest());
System.gc();
}
運行結(jié)果:有輸出
進行GC操作雖然內(nèi)存足夠腔呜,但是對象也被回收了。
--------obj is gc--------
虛引用
這個級別的引用是最低的豆挽,具有這個級別的引用和沒被引用一樣育谬,隨時都有可能被GC掉券盅。虛引用必須和引用隊列 (ReferenceQueue)聯(lián)合使用帮哈。當(dāng)垃圾回收器準備回收一個對象時,如果發(fā)現(xiàn)它還有虛引用锰镀,就會在回收對象的內(nèi)存之前娘侍,把這個虛引用加入到與之 關(guān)聯(lián)的引用隊列中。
@Test
public void onRTre() {
PhantomReference reference = new PhantomReference(new DataTest(),new ReferenceQueue());
System.gc();
}
運行結(jié)果:有輸出進行GC操作雖然內(nèi)存足夠泳炉,但是對象也被回收了憾筏。
--------obj is gc--------
總結(jié)
根據(jù)上面的實驗結(jié)果可以得出下面的區(qū)別
級別 | 回收時機 | 用途 | 存活時間 |
---|---|---|---|
強引用 | 從來不會 | 一般使用 | JVM終止時 |
軟引用 | 在內(nèi)存不足時 | 一般時候或者緩存 | 內(nèi)存不足時 |
弱引用 | 垃圾回收時 | 一般使用或者對象緩存 | GC操作時終止 |
虛引用 | 未知 | 未知 | 未知 |