Java垃圾回收機制

垃圾回收

垃圾回收回調(diào)方法:

  • finalize()函數(shù)是在JVM回收內(nèi)存時執(zhí)行的诗充,但JVM并不保證在回收內(nèi)存時一定會調(diào)用finalize()会烙。

JVM的垃圾回收機制:

  • 在內(nèi)存充足的情況下店归,顯式調(diào)用System.gc()(system.gc調(diào)用僅僅是建議虛擬機進行回收趁曼,并不一定馬上會進行g(shù)c)
  • 在內(nèi)存不足的情況下颂碘,垃圾回收將自動運行

對象狀態(tài)

  • 可達狀態(tài):
    有一個以上的引用變量引用此對象

  • 可恢復(fù)狀態(tài):
    如果程序中某個對象不再有任何的引用變量引用它,它將先進入可恢復(fù)狀態(tài),系統(tǒng)的垃圾回收機制準備回收該對象的所占用的內(nèi)存返敬,在回收之前遂庄,系統(tǒng)會調(diào)用finalize()方法進行資源清理,如果資源整理后重新讓一個以上引用變量引用該對象劲赠,則這個對象會再次變?yōu)榭蛇_狀態(tài),否則就會進入不可達狀態(tài)涛目。

  • 不可達狀態(tài):
    當對象的所有關(guān)聯(lián)都被切斷,且系統(tǒng)調(diào)用finalize()方法進行資源清理后依舊沒有使該對象變?yōu)榭蛇_狀態(tài)凛澎,則這個對象將永久性失去引用并且變成不可達狀態(tài)霹肝,系統(tǒng)才會真正的去回收該對象所占用的資源。

引用

級別: 強引用 > 軟引用 > 弱引用 > 虛引用

StrongReference

默認引用實現(xiàn),當沒有任何對象指向它時预厌,GC執(zhí)行后將會被回收

Food food = new Food();
food = null;

WeakReference

所引用的對象在JVM內(nèi)不再有強引用時,GC執(zhí)行后將會被回收

處理過程:

  • WeakReference對象的referent域被設(shè)置為null阿迈,從而使該對象不再引用heap對象元媚。
  • WeakReference引用過的heap對象被聲明為finalizable轧叽。
  • 同時或者一段時間后WeakReference對象被添加到它的ReferenceQueue(如果ReferenceQueue存在的話)。

對于軟引用和弱引用刊棕,入隊和finalize方法的執(zhí)行是沒有固定順序的

 Food food = new Food();
 WeakReference<Food> weakFood = new      WeakReference<Food>(food);
 food = null;

使用:隨時取得某對象的信息(不影響此對象的垃圾收集)

A obj = new A();
WeakReference wr = new WeakReference(obj);
obj = null;
//等待一段時間炭晒,obj對象就會被垃圾回收
...
if (wr.get()==null) {
  System.out.println("obj 已經(jīng)被清除了 ");} else {
  System.out.println("obj 尚未被清除,其信息是 "+obj.toString());
}

SoftReference

類似WeakReference,但SoftReference會盡可能長的保留引用直到JVM內(nèi)存不足時才會被回收, 適合緩存應(yīng)用

處理過程同WeakReference

Food food = new Food();
SoftReference<Food> softFood = new  SoftReference<Food>(food);
food = null;
// JVM OutOfMemory

使用:簡單對象cache

A obj = new A();
SoftRefenrence sr = new SoftReference(obj);
//引用時
if(sr!=null){
   obj = sr.get();
}else{
  obj = new A();
  sr = new SoftReference(obj);
}

PhantomReference

跟蹤referent何時被enqueue到ReferenceQueue中,它唯一的目的就是對象被回收時能收到一個通知甥角,用于追蹤對象被垃圾回收的狀態(tài)网严,需要和引用隊列ReferenceQueue類聯(lián)合使用。

不建議使用,有潛在的內(nèi)存泄露風(fēng)險,因為JVM不會自動幫助我們釋放,我們必須要保證它指向的堆對象是不可達的

虛引用帶來的內(nèi)存泄露風(fēng)險參考:java中虛引用PhantomReference與弱引用WeakReference(軟引用SoftReference)的差別嗤无。

軟引用和弱引用差別不大震束,JVM都是先將其referent字段設(shè)置成null,之后將軟引用或弱引用当犯,加入到關(guān)聯(lián)的引用隊列中垢村。我們可以認為JVM先回收堆對象占用的內(nèi)存,然后才將軟引用或弱引用加入到引用隊列嚎卫。

而虛引用則不同嘉栓,JVM不會自動將虛引用的referent字段設(shè)置成null,而是先保留堆對象的內(nèi)存空間拓诸,直接將PhantomReference加入到關(guān)聯(lián)的引用隊列侵佃,也就是說如果我們不手動調(diào)用PhantomReference.clear(),虛引用指向的堆對象內(nèi)存是不會被釋放的奠支。

處理過程:

  • 不把referent設(shè)置為null.
  • PhantomReference引用過的heap對象處理到finalized狀態(tài),即調(diào)用了finalize()方法.
  • heap對象被釋放之前把PhantomRefrence對象添加到它的ReferenceQueue中.

摘錄部分蓋樓評論:
我覺得其實是這樣馋辈,其實GC做的工作分成是兩部分,第一部分是將對象從finalizable狀態(tài)到finalized狀態(tài)倍谜,這只是完成了資源的釋放首有;第二部分是reclaimed對象占用的內(nèi)存燕垃。其實所有在ref中的三種reference的referent的對象的reclaimed都只有在相應(yīng)reference對象的clear方法調(diào)用之后,才能進行井联,所以卜壕,GC只是保證weakreference、softreference的clear方法被GC自動調(diào)用烙常,并被加到referencequeue中轴捎,但是phantomreference對象在被加入到referencequeue中之前對象就已經(jīng)被GC finalied(如果定義了finalize方法的話,我所指的finalized是指調(diào)用了finalize方法)了蚕脏,只是還沒有進行第二步reclaimed侦副,因為phantomreference對象的clear方法還沒有被調(diào)用,所以不能進行reclaimed驼鞭。

  Food food = new Food();
  PhantomReference<Food> phantomFood = new PhantomReference<Food>(food, new ReferenceQueue<Food>()); 
  food = null;

使用:

  • Object的finalize方法在回收之前調(diào)用秦驯,若在finalize方法內(nèi)創(chuàng)建此類的強引用會導(dǎo)致對象無法回收,可能引發(fā)JVM OutOfMemory
  • PhantomReference在finalize方法執(zhí)行后進行回收挣棕,避免上述問題

??參考網(wǎng)頁關(guān)于虛引用PhantomReference

@SuppressWarnings("static-access")
public static void main(String[] args) throws Exception {
    String abc = new String("abc");
    System.out.println(abc.getClass() + "@" + abc.hashCode());
    final ReferenceQueue<String> referenceQueue = new ReferenceQueue<String>();
    new Thread() {
        public void run() {
            while (isRun) {
                Object obj = referenceQueue.poll();
                if (obj != null) {
                    try {
                        Field rereferent = Reference.class
                                .getDeclaredField("referent");
                        rereferent.setAccessible(true);
                        Object result = rereferent.get(obj);
                        System.out.println("gc will collect:"
                                + result.getClass() + "@"
                                + result.hashCode() + "\t"
                                + (String) result);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }.start();
    PhantomReference<String> abcWeakRef = new PhantomReference<String>(abc,
            referenceQueue);
    abc = null;
    Thread.currentThread().sleep(3000);
    System.gc();
    Thread.currentThread().sleep(3000);
    isRun = false;
}

總結(jié)

  • 強引用指向的對象如果被引用,發(fā)生GC時是不會被回收的译隘,除非該對象沒有被引用
  • 軟引用在內(nèi)存非常緊張的時候會被回收(無引用),其他時候不會被回收洛心,所以在使用之前要判斷是否為null從而判斷他是否已經(jīng)被回收了
  • 弱引用和虛引用指向的對象(無引用)在發(fā)生GC時一定會被回收
  • 通過虛引用得不到引用的對象實例,虛引用的get()方法永遠返回null

參考

Java的內(nèi)存回收機制
Java中三個引用類SoftReference 固耘、 WeakReference 和 PhantomReference的區(qū)別
Java引用
引用
Java幽靈引用的作用

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市词身,隨后出現(xiàn)的幾起案子厅目,更是在濱河造成了極大的恐慌,老刑警劉巖法严,帶你破解...
    沈念sama閱讀 211,376評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件损敷,死亡現(xiàn)場離奇詭異,居然都是意外死亡深啤,警方通過查閱死者的電腦和手機拗馒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來墓塌,“玉大人瘟忱,你說我怎么就攤上這事∩淮保” “怎么了访诱?”我有些...
    開封第一講書人閱讀 156,966評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長韩肝。 經(jīng)常有香客問我触菜,道長,這世上最難降的妖魔是什么哀峻? 我笑而不...
    開封第一講書人閱讀 56,432評論 1 283
  • 正文 為了忘掉前任涡相,我火速辦了婚禮哲泊,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘催蝗。我一直安慰自己切威,他們只是感情好,可當我...
    茶點故事閱讀 65,519評論 6 385
  • 文/花漫 我一把揭開白布丙号。 她就那樣靜靜地躺著先朦,像睡著了一般。 火紅的嫁衣襯著肌膚如雪犬缨。 梳的紋絲不亂的頭發(fā)上喳魏,一...
    開封第一講書人閱讀 49,792評論 1 290
  • 那天,我揣著相機與錄音怀薛,去河邊找鬼刺彩。 笑死,一個胖子當著我的面吹牛枝恋,可吹牛的內(nèi)容都是我干的创倔。 我是一名探鬼主播,決...
    沈念sama閱讀 38,933評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼鼓择,長吁一口氣:“原來是場噩夢啊……” “哼三幻!你這毒婦竟也來了就漾?” 一聲冷哼從身側(cè)響起呐能,我...
    開封第一講書人閱讀 37,701評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎抑堡,沒想到半個月后摆出,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,143評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡首妖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,488評論 2 327
  • 正文 我和宋清朗相戀三年偎漫,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片有缆。...
    茶點故事閱讀 38,626評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡象踊,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出棚壁,到底是詐尸還是另有隱情杯矩,我是刑警寧澤,帶...
    沈念sama閱讀 34,292評論 4 329
  • 正文 年R本政府宣布袖外,位于F島的核電站史隆,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏曼验。R本人自食惡果不足惜泌射,卻給世界環(huán)境...
    茶點故事閱讀 39,896評論 3 313
  • 文/蒙蒙 一粘姜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧熔酷,春花似錦孤紧、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至翼抠,卻和暖如春咙轩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背阴颖。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工活喊, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人量愧。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓钾菊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親偎肃。 傳聞我的和親對象是個殘疾皇子煞烫,可洞房花燭夜當晚...
    茶點故事閱讀 43,494評論 2 348

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

  • 1. 垃圾回收的意義在C++中,對象所占的內(nèi)存在程序結(jié)束運行之前一直被占用累颂,在明確釋放之前不能分配給其它對象滞详;而在...
    愛情小傻蛋閱讀 922評論 0 11
  • 來自: Android夢想特工隊作者: Aaron主頁: http://www.wxtlife.com/原...
    技術(shù)特工隊閱讀 4,361評論 0 28
  • 1.什么是垃圾回收? 垃圾回收(Garbage Collection)是Java虛擬機(JVM)垃圾回收器提供...
    簡欲明心閱讀 89,449評論 17 311
  • 一紊馏、垃圾回收機制的意義Java語言中一個顯著的特點就是引入了垃圾回收機制料饥,使c++程序員最頭疼的內(nèi)存管理的問題迎刃...
    任任任任師艷閱讀 632評論 0 0
  • 1. 我和妻子結(jié)婚的第二個月,她就忍受不了在家平靜的生活朱监,非要拉著我去外面走走岸啡。我正在公司加班,短信問她赫编,要去哪里...
    陳汐年閱讀 750評論 10 24