Java垃圾收集算法—深入理解Java虛擬機(七)

Java Java虛擬機 編程語言 IBM 小瘋子程序員 小瘋子程序員 2017-09-25

前言

繼續上一講內容,繼續深入Java虛擬機,講述基礎內容,在趨勢的面試中,贏就應在Java虛擬機的認知,所以把這個非常重要的知識點拿出來跟大家分享一起學習。

現在講的都是最實用的,下面講的都是重點,每一點都要牢記。

正文

  1. 垃圾收集法

1.1 標記-清除算法

這個應該很容易理解了,標記需要清除的對象,然後直接清理掉,如何標記,在上一講中介紹的很仔細了,沒注意的作者可以回頭再翻看一下,就在上一節,這是最基礎的算法了,後面的收集法也都是基於這種思路的,但是它有它的缺點:標記跟清理的效率都很低,還有就是上一節談過的,標記清理使得內存不規整,如果出現需要分配大內存的情況下,連續的內存不足,那就要觸發垃圾收集器回收,而過多的垃圾收集,造成資源浪費,耗費時間,次數多了,影響程序運行流暢。

Java垃圾收集算法—深入理解Java虛擬機(七)

標記清除算法

1.2 複製算法

由於前一種內存碎片化的問題,所以帶來了第二種方法,複製發,依然很容易理解,將內存分成相同的兩塊,先集中在一塊內存上分配,當垃圾收集器回收以後,將存活的對象複製到另一塊內存上保存,這樣可以保證內存的有序性,實現簡單,運行高效,但是這種方法,需要將可用內存大小犧牲一半,內存的容量減小,也會增加垃圾收集器工作次數。

Java垃圾收集算法—深入理解Java虛擬機(七)

複製算法

現在的商業虛擬機都採用這種收集算法來回收新生代,IBM公司的專門研究表明,新生代中的對象98%是“朝生夕死”的,所以並不需要按照1:1的比例來劃分內存空間,而是將內存分為一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden和其中一塊Survivor[1]。當回收時,將Eden和Survivor中還存活著的對象一次性地複製到另外一塊Survivor空間上,最後清理掉Eden和剛才用過的Survivor空間。 HotSpot虛擬機默認Eden和Survivor的大小比例是8:1,也就是每次新生代中可用內存空間為整個新生代容量的90%(80%+10%),只有10%的內存會被“浪費”。 當然,98%的對象可回收只是一般場景下的數據,我們沒有辦法保證每次回收都只有不多於10%的對象存活,當Survivor空間不夠用時,需要依賴其他內存(這裡指老年代)進行分配擔保(Handle Promotion)。

1.3 標記-整理

複製收集算法在對象存活率較高時就要進行較多的複製操作,效率將會變低。 更關鍵的是,如果不想浪費50%的空間,就需要有額外的空間進行分配擔保,以應對被使用的內存中所有對象都100%存活的極端情況,老年代對象存活的比較多,採用複製算法,效率不好。

針對存活內存塊上存活對象多的情況下,提出了標記-整理法,標記過程仍然與“標記-清除”算法一樣,但後續步驟不是直接對可回收對象進行清理,而是讓所有存活的對象都向一端移動,然後直接清理掉端邊界以外的內存。

Java垃圾收集算法—深入理解Java虛擬機(七)

標記-整理算法

1.4 分代回收

當前商業虛擬機的垃圾收集都採用“分代收集”(Generational Collection)算法,這種算法並沒有什麼新的思想,只是根據對象存活週期的不同將內存劃分為幾塊。 一般是把Java堆分為新生代和老年代,這樣就可以根據各個年代的特點採用最適當的收集算法。 在新生代中,每次垃圾收集時都發現有大批對象死去,只有少量存活,那就選用複製算法,只需要付出少量存活對象的複製成本就可以完成收集。 而老年代中因為對象存活率高、 沒有額外空間對它進行分配擔保,就必須使用“標記—清理”或者“標記—整理”算法來進行回收。

下一節會比較枯燥一點,但是大家應該關注不多,對於算法的執行效率,以及垃圾收集器是怎麼進行收集的?感興趣的記得關注收藏!

相關推薦

推薦中...