垃圾收集算法

因爲垃圾收集算法的實現涉及大量的程序細節,並且各個平臺的虛擬機操做內存的方法又各不相同,所以不打算過多地討論算法地實現,只是介紹幾種算法地思想及其發展過程。算法

標記-清除算法

最基礎地收集算法是「標記-清除」(Mark-Sweep)算法,算法分爲」標記「和」清除「兩個階段:首先標記出全部須要回收的對象,在標記完成後統一回收掉全部被標記地對象,它地標記過程其實在前一節講述對象標記斷定時已經基本介紹過了。它地主要缺點有兩個:一個是效率問題,標記和清除過程地效率都不高;另一個是空間問題,標記清除以後會產生大量不連續地內存碎片,空間碎片太多可能會致使,當前程序在之後地運行過程當中須要分配較大對象時沒法找到足夠地連續內存而不得不提早觸發另外一次垃圾收集動做。標記-清除算法的執行過程如圖所示。指針

複製算法

爲了解決效率問題,一種稱爲」複製「(Copying)的收集算法出現了,它將可用內存按容量劃分爲大小相等的兩塊,每次只使用其中的一塊。當這一塊的內存用完了,就將還存活着的對象複製到另一塊上面,而後再把已使用過的內存空間一次清理掉。這樣使得每次都是對其中的一塊進行內存回收,內存分配時也就不用考慮內存碎片等複雜狀況,只要移動堆頂指針,按順序分配內存便可,實現簡單,運行高效。只是這種算法的代價是將內存縮小爲原來的一半,未免過高了一點。對象

複製算法的執行過程如圖所示:blog

如今的商業虛擬機都採用這種收集算法來回收新生代,IBM的專門研究代表,新生代中的對象98%是朝生夕死的,因此並不須要按照1:1的比例來劃份內存空間,而是將內存分爲一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden和其中的一塊Survivor。當回收時,將Eden和Survivor中還存活着的對象一次性拷貝到另一塊Survivor空間上,最後清理掉Eden和剛纔用過的Survivor的空間。內存

內存的分配擔保就比如咱們去銀行借款,若是咱們信譽很好,在98%的狀況下都能按時償還,因而銀行可能會默認咱們下一次也能按時按量地償還貸款,只須要有一個擔保人能保證若是我不能還款時,能夠從他地帳戶扣錢,那銀行就認爲沒有風險了。內存的分配擔保也同樣,入宮另一塊Survivor空間沒有足夠的空間存放上一次新生代收集下來的存活對象,這些對象將直接經過分配擔保機制進入老年代。虛擬機

標記-整理算法

複製收集算法在對象存活率較高時就要執行較多的複製操做,效率將會變低。更關鍵的是,若是不想浪費50%的空間,就須要有額外的空間進行分配擔保,以應對被使用的內存中全部對象都100%存活的極端狀況,因此在老年代通常不能直接選用這種算法。io

根據這一特色,有人提出了另一種「標記-整理」(Mark-Compact)算法,標記過程仍然與「標記-清除」算法同樣,但後續步驟不是直接對可回收對象進行清理,而是讓全部存活的對象都向一端移動,而後直接清理掉邊界之外的內存,「標記-整理」算法的示意圖如圖所示:效率

分代收集算法

當前商業虛擬機的垃圾收集都採用「分代收集」(Generational Colletion)算法,這種算法並無什麼新的思想,只是根據對象的存活週期的不一樣將內存劃分爲幾塊。通常是把Java堆分爲新生代和老生代,這樣就能夠根據各個年代的特色採用最適當的收集算法。在新生代中,每次垃圾收集時都發現有大批對象死去,只有少許存活,那就選用複製算法,只須要付出少許存活對象的複製成本就能夠完成收集。而老年代中由於對象存活率高、沒有額外空間對它進行分配擔保,就必須使用「標記-清理」或「標記-整理」算法來進行回收。基礎

相關文章
相關標籤/搜索