Java的記憶體回收(Garbage Collection)機制

來源:互聯網
上載者:User

一。誰在做Garbage Collection?

    一種流行的說法:在C++
裡,是系統在做記憶體回收;而在Java
裡,是Java
自身在做。

    在C++
裡,
釋放記憶體是手動處理的,要用delete運算子來釋放分配的記憶體。這是流行的說法。確切地說,是應用認為不需要某實體時,就需用delete告訴系統,可
以回收這塊空間了。這個要求,對編碼者來說,是件很麻煩、很難做到的事。隨便上哪個BBS,在C/C++版塊裡總是有一大堆關於記憶體流失的話題。

    Java採用一種不同的,很方便的方法:Garbage Collection.記憶體回收機制放在JVM裡。JVM完全負責記憶體回收事宜,應用只在需要時申請空間,而在拋棄對象時不必關心空間回收問題。

    二。對象在啥時被丟棄?

    在C++裡,當對象離開其範圍時,該對象即被應用拋棄。

    是對象的生命期不再與其範圍有關,而僅僅與引用有關。

    Java的記憶體回收機制一般包含近十種演算法。對這些演算法中的多數,我們不必予以關心。只有其中最簡單的一個:引用計數法,與編碼有關。

    一個對象,可以有一個或多個引用變數指向它。當一個對象不再有任何一個引用變數指向它時,這個對象就被應用拋棄了。或者說,這個對象可以被記憶體回收機制回收了。

    這就是說,當不存在對某對象的任何引用時,就意味著,應用告訴JVM:我不要這個對象,你可以回收了。

    JVM的記憶體回收機制對堆空間做即時檢測。當發現某對象的引用計數為0時,就將該對象列入待回收列表中。但是,並不是馬上予以銷毀。

    三。丟棄就被回收?

    該對象被認定為沒有存在的必要了,那麼它所佔用的記憶體就可以被釋放。被回收的記憶體可以用於後續的再分配。

    但是,並不是對象被拋棄後當即被回收的。JVM進程做空間回收有較大的系統開銷。如果每當某應用進程丟棄一個對象,就立即回收它的空間,勢必會使整個系統的運轉效率非常低下。

    前面說過,JVM的記憶體回收機制有多個演算法。除了引用計數法是用來判斷對象是否已被拋棄外,其它演算法是用來確定何時及如何做回收。JVM的記憶體回收機制要在時間和空間之間做個平衡。

    因此,為了提高系統效率,記憶體回收行程通常只在滿足兩個條件時才運行:即有對象要回收且系統需要回收。切記記憶體回收要佔用時間,因此,Java運行時系統只在需要的時候才使用它。因此你無法知道記憶體回收發生的精確時間。

    四。沒有引用變數指向的對象有用嗎?

    前面說了,沒掛上引用變數的對象是被應用丟棄的,這意味著,它在堆空間裡是個垃圾,隨時可能被JVM回收。

    不過,這裡有個不是例外的例外。對於一次性使用的對象(有些書稱之為臨時對象),可以不用引用變數指向它。舉個最簡單也最常見的例子:

    System.out.println(“I am Java!”);

    就是建立了一個字串對象後,直接傳遞給println()方法。

    五。應用能干預記憶體回收嗎?

   
許多人對Java的記憶體回收不放心,希望在應用代碼裡控制JVM的記憶體回收運作。這是不可能的事。對記憶體回收機制來說,應用只有兩個途徑發訊息給JVM.
第一個前面已經說了,就是將指向某對象的所有引用變數全部移走。這就相當於向JVM發了一個訊息:這個對象不要了。第二個是調用庫方法
System.gc(),多數書裡說調用它讓Java做記憶體回收。

    第一個是一個告知,而調用System.gc()也僅僅是一個請求。JVM接受這個訊息後,並不是立即做記憶體回收,而只是對幾個記憶體回收演算法做了加權,使記憶體回收操作容易發生,或提早發生,或回收較多而已。

    希望JVM及時回收垃圾,是一種需求。其實,還有相反的一種需要:在某段時間內最好不要回收垃圾。要求運行速度最快的即時系統,特別是嵌入式
系統,往往希望如此。

    Java的記憶體回收機制是為所有Java應用進程服務的,而不是為某個特定的進程服務的。因此,任何一個進程都不能命令記憶體回收機製做什麼、怎麼做或做多少。

    六。對象被回收時要做的事

    一個對象在運行時,可能會有一些東西與其關連。因此,當對象即將被銷毀時,有時需要做一些善後工作。可以把這些操作寫在finalize()方法(常稱之為終止器)裡。

    protected void finalize()

    {

    // finalization code here

    }

   
這個終止器的用途類似於C++裡的解構函式,而且都是自動調用的。但是,兩者的調用時機不一樣,使兩者的表現行為有重大區別。C++的解構函式總是當對象
離開範圍時被調用。這就是說,C++解構函式的調用時機是確定的,且是可被應用判知的。但是,Java終止器卻是在對象被銷毀時。由上所知,被丟棄的對
象何時被銷毀,應用是無法獲知的。而且,對於大多數場合,被丟棄對象在應用終止後仍未銷毀。

   
在編碼時,考慮到這一點。譬如,某對象在運作時開啟了某個檔案,在對象被丟棄時不關閉它,而是把檔案關閉語句寫在終止器裡。這樣做對檔案操作會造成問題。
如果檔案是獨佔開啟的,則其它對象將無法訪問這個檔案。如果檔案是共用開啟的,則另一訪問該檔案的對象直至應用終結仍不能讀到被丟棄對象寫入該檔案的新內
容。

    至少對於檔案操作,編碼者應認清Java終止器與C++解構函式之間的差異。

    那麼,當應用終止,會不會執行應用中的所有finalize()呢?據Bruce Eckel在Thinking in Java裡的觀點:“到程式結束的時候,並非所有收尾模組都會得到調用”。這還僅僅是指應用正常終止的場合,非正常終止呢?

    因此,哪些收尾操作可以放在finalize()裡,是需要酌酎的。

 

 

 

 

 

 

 

 

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.