Java關(guān)于強(qiáng)引用授滓、軟引用琳水、弱引用和虛引用的區(qū)別與用法

一.概述

眾所周知,Java中是JVM負(fù)責(zé)內(nèi)存的分配和回收褒墨,這是它的優(yōu)點(diǎn)(使用方便炫刷,程序不用再像使用C那樣操心內(nèi)存),但同時(shí)也是它的缺點(diǎn)(不夠靈活)郁妈。為了解決你存操作不靈活這個(gè)問題浑玛,可以采用軟引用等方法。
在JDK1.2以前的版本中噩咪,當(dāng)一個(gè)對(duì)象不被任何變量引用顾彰,那么程序就無法再使用這個(gè)對(duì)象。也就是說胃碾,只有對(duì)象處于可觸及狀態(tài)涨享,程序才能使用它。這就像日常生活中仆百,從商店購(gòu)買了某件物品后厕隧,如果有用,就一直保留它,否則就把它扔到垃圾桶吁讨,由清潔工人收走髓迎。一般說來,如果物品已經(jīng)被扔到垃圾箱建丧,想再把它撿回來使用就不太可能了排龄。
但有時(shí)候情況并不這么簡(jiǎn)單,你可能會(huì)遇到類似雞肋一樣的物品翎朱,食之無味橄维,棄之可惜。這種物品現(xiàn)在已經(jīng)無用了拴曲,保留它會(huì)占空間争舞,但是立刻扔掉它也不劃算,因?yàn)橐苍S將來還會(huì)派上用場(chǎng)疗韵。對(duì)于這樣的可有可無的物品兑障,一種折衷的處理辦法是:如果家里空間足夠,就先把它保留再家里蕉汪,如果家里空間不夠流译,即使把家里所有垃圾清除,還是無法容納那些必不可少的生活用品者疤,那么再扔掉這些可有可無的物品福澡。
從JDK1.2版本開始,把對(duì)象的引用分為四種級(jí)別驹马,從而使程序能更加靈活的控制對(duì)象的生命周期革砸。這四種級(jí)別由高到低依次為:強(qiáng)引用、軟引用糯累、弱引用和虛引用算利。

二、具體描述:

1.強(qiáng)引用
以前我們使用的大部分引用實(shí)際上都是強(qiáng)引用泳姐,這是使用最普遍的引用效拭。如果一個(gè)對(duì)象具有強(qiáng)引用,那就類似于必不可少的生活用品胖秒,垃圾回收器絕不會(huì)回收它缎患。當(dāng)你存空間不足,Java虛擬機(jī)寧愿拋出OutOfMemoryError錯(cuò)誤阎肝,使程序異常終止挤渔,也不會(huì)靠隨意回收具有強(qiáng)引用的對(duì)象來解決內(nèi)存不足問題。

 String str = "abc";
 List<String> list = new Arraylist<String>();
 list.add(str);

在list集合里的數(shù)據(jù)不會(huì)釋放风题,即使內(nèi)存不足也不會(huì)

在ArrayList類中定義了一個(gè)私有的變量elementData數(shù)組判导,在調(diào)用方法清空數(shù)組時(shí)可以看到為每個(gè)數(shù)組內(nèi)容賦值為null嫉父。不同于elemenData=null,強(qiáng)引用仍然存在,避免在后續(xù)調(diào)用add()等方法添加元素時(shí)進(jìn)行重新的內(nèi)存分配骡楼。使用如clear()方法中釋放內(nèi)存的方法對(duì)數(shù)組中存放的引用類型特別適用熔号,這樣就可以及時(shí)釋放內(nèi)存稽鞭。
2.軟引用(SoftReference)
如果一個(gè)對(duì)象只具有軟引用鸟整,那就類似于可有可無的生活用品。如果內(nèi)存空間不夠朦蕴,垃圾回收器就不會(huì)回收它篮条,如果內(nèi)存空間不足了,就會(huì)回收這些對(duì)象的內(nèi)存吩抓。只要垃圾回收器沒有回收它涉茧,該對(duì)象就可以被程序使用。軟引用可以用來實(shí)現(xiàn)內(nèi)存敏感的高速緩存疹娶。
軟引用可以和一個(gè)引用隊(duì)列(ReferenceQueue)聯(lián)合使用伴栓,如果軟引用所引用的對(duì)象被垃圾回收,JAVA虛擬機(jī)就會(huì)把這個(gè)軟引用加入到與之關(guān)聯(lián)的引用隊(duì)列中雨饺。
如:

public class Test {  

    public static void main(String[] args){  
        System.out.println("開始");            
        A a = new A();            
        SoftReference<A> sr = new SoftReference<A>(a);  
        a = null;  
        if(sr!=null){  
            a = sr.get();  
        }  
        else{  
            a = new A();  
            sr = new SoftReference<A>(a);  
        }            
        System.out.println("結(jié)束");     
    }       

}  

class A{  
    int[] a ;  
    public A(){  
        a = new int[100000000];  
    }  
} 

當(dāng)內(nèi)存足夠大時(shí)可以把數(shù)組存入軟引用钳垮,取數(shù)據(jù)時(shí)就可從內(nèi)存里取數(shù)據(jù),提高運(yùn)行效率
軟引用在實(shí)際中有重要的應(yīng)用额港,例如瀏覽器的后退按鈕饺窿。
按后退時(shí),這個(gè)后退時(shí)顯示的網(wǎng)頁(yè)內(nèi)容是重新進(jìn)行請(qǐng)求還是從緩存中取出呢移斩?這就要看具體的實(shí)現(xiàn)策略了肚医。

(1)如果一個(gè)網(wǎng)頁(yè)在瀏覽結(jié)束時(shí)就進(jìn)行內(nèi)容的回收,則按后退查看前面瀏覽過的頁(yè)面時(shí)向瓷,需要重新構(gòu)建
(2)如果將瀏覽過的網(wǎng)頁(yè)存儲(chǔ)到內(nèi)存中會(huì)造成內(nèi)存的大量浪費(fèi)肠套,甚至?xí)斐蓛?nèi)存溢出
這時(shí)候就可以使用軟引用
3.弱引用(WeakReference)
如果一個(gè)對(duì)象只具有弱引用,那就類似于可有可無的生活用品猖任。弱引用與軟引用的區(qū)別在于:只具有弱引用的對(duì)象擁有更短的生命周期你稚。在垃圾回收器線程掃描它所管轄的內(nèi)存區(qū)域的過程中,一旦發(fā)現(xiàn)了只具有弱引用的對(duì)象超升,不管當(dāng)前內(nèi)存空間足夠與否入宦,都會(huì)回收它的內(nèi)存。不過室琢,由于垃圾回收器是一個(gè)優(yōu)先級(jí)很低的線程乾闰,因此不一定會(huì)很快發(fā)現(xiàn)那些只具有弱引用的對(duì)象。
弱引用可以和一個(gè)引用隊(duì)列(ReferenceQueue)聯(lián)合使用盈滴,如果弱引用所引用的對(duì)象被垃圾回收涯肩,Java虛擬機(jī)就會(huì)把這個(gè)弱引用加入到與之關(guān)聯(lián)的引用隊(duì)列中轿钠。
如:

Object c = new Car(); //只要c還指向car object, car object就不會(huì)被回收
WeakReference<Car> weakCar = new WeakReference(Car)(car);

當(dāng)要獲取weak reference引用的object時(shí),首先需要判斷它是否已經(jīng)被回收:

weakCar.get();

如果此方法為空病苗,那么說明weakCar指向的對(duì)象已經(jīng)被回收了疗垛,下面來看一個(gè)例子:

public class Car {
  private double price;
  private String colour;

  public Car(double price, String colour){
    this.price = price;
    this.colour = colour;
  }

  public double getPrice() {
    return price;
  }
  public void setPrice(double price) {
    this.price = price;
  }
  public String getColour() {
    return colour;
  }
  public void setColour(String colour) {
    this.colour = colour;
  }

  public String toString(){
    return colour +"car costs $"+price;
  }

}


public class TestWeakReference {


  public static void main(String[] args) {

    Car car = new Car(22000,"silver");
    WeakReference<Car> weakCar = new WeakReference<Car>(car);

    int i=0;

    while(true){
      if(weakCar.get()!=null){
        i++;
        System.out.println("Object is alive for "+i+" loops - "+weakCar);
      }else{
        System.out.println("Object has been collected.");
        break;
      }
    }
  }

}

在上例中,程序運(yùn)行一段時(shí)間后硫朦,程序打印出“Object has been collected.” 說明贷腕,weak reference指向的對(duì)象的被回收了
如果要想打出的是 Object is alive for "+i+" loops - "+ weakCar
那么只要在這句話前面加上 System.out.println("car=== "+car);
因?yàn)樵诖藦?qiáng)引用了car對(duì)象

如果這個(gè)對(duì)象是偶爾的使用,并且希望在使用時(shí)隨時(shí)就能獲取到咬展,但又不想影響此對(duì)象的垃圾收集泽裳,那么你應(yīng)該用WeakReference來記住此對(duì)象。
當(dāng)你想引用一個(gè)對(duì)象破婆,但是這個(gè)對(duì)象有自己的生命周期涮总,你不想介入這個(gè)對(duì)象的生命周期,這時(shí)候你就是用弱引用祷舀。
這個(gè)引用不會(huì)在對(duì)象的垃圾回收判斷中產(chǎn)生任何附加的影響瀑梗。
4.虛引用(PhantomReference)
"虛引用"顧名思義,就是形同虛設(shè)裳扯,與其他幾種引用都不同抛丽,虛引用并不會(huì)決定對(duì)象的生命周期。如果一個(gè)對(duì)象僅持有虛引用嚎朽,那么它就和沒有任何引用一樣铺纽,在任何時(shí)候都可能被垃圾回收。虛引用主要用來跟蹤對(duì)象被垃圾回收的活動(dòng)哟忍。虛引用與軟引用和弱引用的一個(gè)區(qū)別在于:虛引用必須和引用隊(duì)列(ReferenceQueue)聯(lián)合使用狡门。當(dāng)垃圾回收器準(zhǔn)備回收一個(gè)對(duì)象時(shí),如果發(fā)現(xiàn)它還有虛引用锅很,就會(huì)在回收對(duì)象的內(nèi)存之前其馏,把這個(gè)虛引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。程序可以通過判斷引用隊(duì)列中是否已經(jīng)加入了虛引用爆安,來了解被引用的對(duì)象是否將要被垃圾回收叛复。程序如果發(fā)現(xiàn)某個(gè)虛引用已經(jīng)被加入到引用隊(duì)列,那么就可以在所引用的對(duì)象的內(nèi)存被回收之前采取必要的行動(dòng)扔仓。
特別注意褐奥,在實(shí)際程序設(shè)計(jì)中一般很少使用弱引用與虛引用,使用軟引用的情況較多翘簇,這是因?yàn)檐浺每梢约铀貸VM對(duì)垃圾內(nèi)存的回收速度撬码,可以維護(hù)系統(tǒng)的運(yùn)行安全,防止內(nèi)存溢出(OutOfMemory)等問題的產(chǎn)生版保。
總結(jié)
強(qiáng)引用:
String str = "adb";
list.add(str);
軟引用:
如果弱引用對(duì)象回收完之后呜笑,內(nèi)存還是報(bào)警夫否,繼續(xù)回收軟引用對(duì)象
弱引用:
如果虛引用對(duì)象回收完之后,內(nèi)存還是報(bào)警叫胁,繼續(xù)回收弱引用對(duì)象
虛引用:
虛擬機(jī)的內(nèi)存不夠使用凰慈,開始報(bào)警,這時(shí)候垃圾回收機(jī)制開始執(zhí)行System.gc(); String s = "adb";如果沒有對(duì)象回收了驼鹅,就回收沒虛引用的對(duì)象

引用類型 被垃圾回收時(shí)間 用途 生存時(shí)間
強(qiáng)引用 從來不會(huì) 對(duì)象的一般狀態(tài) JVM停止運(yùn)行時(shí)終止
軟引用 在內(nèi)存不足時(shí) 對(duì)象緩存 內(nèi)存不足時(shí)終止
弱引用 在垃圾回收時(shí) 對(duì)象緩存 gc運(yùn)行后終止
虛引用 Unknown Unknown Unknown
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末微谓,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子谤民,更是在濱河造成了極大的恐慌堰酿,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件张足,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡坎藐,警方通過查閱死者的電腦和手機(jī)为牍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來岩馍,“玉大人碉咆,你說我怎么就攤上這事≈鳎” “怎么了疫铜?”我有些...
    開封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)双谆。 經(jīng)常有香客問我壳咕,道長(zhǎng),這世上最難降的妖魔是什么顽馋? 我笑而不...
    開封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任谓厘,我火速辦了婚禮,結(jié)果婚禮上寸谜,老公的妹妹穿的比我還像新娘竟稳。我一直安慰自己,他們只是感情好熊痴,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開白布他爸。 她就那樣靜靜地躺著,像睡著了一般果善。 火紅的嫁衣襯著肌膚如雪诊笤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天岭埠,我揣著相機(jī)與錄音盏混,去河邊找鬼蔚鸥。 笑死,一個(gè)胖子當(dāng)著我的面吹牛许赃,可吹牛的內(nèi)容都是我干的止喷。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼混聊,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼弹谁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起句喜,我...
    開封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤预愤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后咳胃,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體植康,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年展懈,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了销睁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡存崖,死狀恐怖冻记,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情来惧,我是刑警寧澤冗栗,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站供搀,受9級(jí)特大地震影響隅居,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜趁曼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一军浆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧挡闰,春花似錦乒融、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至奢驯,卻和暖如春申钩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瘪阁。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工撒遣, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留邮偎,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓义黎,卻偏偏與公主長(zhǎng)得像禾进,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子廉涕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容