更新時間:2021-10-22 來源:黑馬程序員 瀏覽量:
垃圾收集算法有標記-清除算法、復制算法、標記真理算法、分代收集算法四種,下面我們詳細介紹。
標記-清除算法:
最基礎的收集算法是標記-清除算法,如同它的名字一樣,分為標記和清除兩個階段。第一步標記出所要回收的對象,在標記完成后統一回收所有被標記的對象。如何標記已經在上面說過了,之所以說它是最基本的垃圾收集算法,原因在于其他的算法也是基于這種思路并對其不足做以改進得到的。
主要問題有兩個:
第一個是效率問題,標記和清除的效率都不高。
第二個是空間分配問題,標記清除后會產生大量的不連續的內存空間,空間碎片太多可能會導致以后程序在運行過程中需要給較大對象分配空間時,無法找到足夠的內存空間,而不得不提前進行一次垃圾收集動作。如圖所示,會產生大量的垃圾碎片,導致空間的利用率不高。
復制算法
為了解決效率問題,一種稱為復制的收集算法出現了,它將可用內存分為大小相等的兩塊,每次只使用其中的一塊,當這一塊內存區域用完了,就將還存活的對象復制到另一塊內存中,然后再把已使用的空間一次性清理掉,這樣每次都是對半個區域進行回收,內存分配時也就不用考慮碎片等問題了,只要移動堆頂指針,按順序分配內存即可,實現簡單,運行高效。
只是這種做法將原來的內存縮小為一半,代價太高了。
現在的商用虛擬機都采用這種方法來回收新生代,IBM專門研究表明,新生代中的對象98%都是"朝生夕死"的,所以并不需要按照1:1劃分內存區域,而是將內存分為一塊較大的區域給Eden和兩塊較小的區域給Survivor,
當回收時,將Eden和Survivor區中還存活的對象一次性復制到另一塊Survivor區,然后將Eden和Survivor區進行一次性清理。Hotspot區默認的Eden和Survivor的比例為8:1,也就是說新生代的可用內存為90%,只有10%的內存會被劃分為保留內存。當然,大多數情況下是98%,但我們不能保證每次回收的存活對象都小于10%,當Survivor區不夠用時,需要依賴其他區域進行分配擔保。如果另外一塊Survivor區已經不夠用了,對象可通過內存擔保機制直接進入到老年代。
標記整理算法
復制算法在存活對象比例比較高的情況下要進行較多的復制操作,效率將會變低,更關鍵的是,如果不想浪費50%的區域,則需要額外的空間進行分配擔保,以應對內存中100%對象都存活的極端情況,所以老年代一般不選用這種算法。
根據老年代的特點,有人提出了另一種標記-整理算法,標記過程與標記-清除算法一致,但后續步驟不是對可回收對象直接進行清理,而是讓所有存活對象都向一端移動,然后直接清理掉邊界外的對象。示意圖如下:
分代收集算法
當前商用的垃圾收集器都采用的是分代垃圾回收,這種算法沒有什么新的思想,只是根據對象的存活周期將內存分為幾塊,一般是將java堆分為新生代和老年代,這樣就可以根據各個代的對象特點選用最適當的回收算法。在新生代,每次垃圾回收都有大量的對象死去,只有少量存活,這樣就適合采用復制算法。只需要付出少量的對象復制成本就可以完成垃圾回收,而老年代因為存活率高,沒有其他內存進行分配擔保,就必須使用標記-清理或者標記-整理進行回收。
1. 分代分為年輕代和老年代,年輕代里頭又分為 Eden區和Survivor區,通常默認的比例為8:1:1, 每次只保留10%的空間用作預留區域,然后將90%的空間可以用作新生對象。
2. 每一次垃圾回收之后,存活的對象年齡對應+1,當經歷15次還依然存活的對象,我們讓它直接進入到老年代;
3. 另外一種進入到老年代的方式是內存擔保機制,也就是當新生代的空間不夠的時候,對象直接進入到老年代;
4. 新生代的垃圾回收叫Minor GC,老年代的叫Full GC。
添加QQ(注意~~添加好友界面,選擇找人):435946716,【免費】獲取《JVM核心教程:JVM從門到精通_JVM虛擬機底層原理深入教程》全套視頻教程+配套資料。
猜你喜歡