算法分爲「標記」和「清除」階段:首先標記出全部須要回收的對象,在標記完成後統一回收全部被標記的對象。它是最基礎的收集算法,效率也很高,可是會帶來兩個明顯的問題:算法
碎片太多可能會致使後續過程當中須要爲大對象分配空間時沒法找到足夠的空間而提早觸發新的一次垃圾收集動做,增長內存回收的次數對象
爲了解決效率問題,「複製」收集算法出現了。它能夠將內存分爲大小相同的兩塊,每次使用其中的一塊。當這一塊的內存使用完後,就將還存活的對象複製到另外一塊去,而後再把使用的空間一次清理掉。這樣就使每次的內存回收都是對內存區間的一半進行回收。內存
這種算法雖然實現簡單,運行高效且不容易產生內存碎片,可是卻對內存空間的使用作出了高昂的代價,由於可以使用的內存縮減到原來的一半。虛擬機
很顯然,Copying算法的效率跟存活對象的數目多少有很大的關係,若是存活對象不少,那麼Copying算法的效率將會大大下降。it
根據老年代的特色特出的一種標記算法,標記過程仍然與「標記-清除」算法同樣,但後續步驟不是直接對可回收對象回收,而是讓全部存活的對象向一端移動,而後直接清理掉端邊界之外的內存。class
分代回收算法其實是把複製算法和標記整理法的結合,並非真正一個新的算法效率
當前虛擬機的垃圾收集都採用分代收集算法,這種算法沒有什麼新的思想,只是根據對象存活週期的不一樣將內存分爲幾塊。通常將 java 堆分爲新生代和老年代,老年代的特色是每次垃圾收集時只有少許對象須要被回收,而新生代的特色是每次垃圾回收時都有大量的對象須要被回收,那麼就能夠根據不一樣代的特色採起最適合的收集算法。基礎
好比在新生代中,每次收集都會有大量對象死去,因此能夠選擇複製算法,只須要付出少許對象的複製成本就能夠完成每次垃圾收集。而老年代的對象存活概率是比較高的,並且沒有額外的空間對它進行分配擔保,因此咱們必須選擇「標記-清除」或「標記-整理」算法進行垃圾收集。變量
目前大部分垃圾收集器對於新生代都採起Copying算法,由於新生代中每次垃圾回收都要回收大部分對象,也就是說須要複製的操做次數較少,可是實際中並非按照1:1的比例來劃分新生代的空間的,通常來講是將新生代劃分爲一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden空間和其中的一塊Survivor空間,當進行回收時,將Eden和Survivor中還存活的對象複製到另外一塊Survivor空間中,而後清理掉Eden和剛纔使用過的Survivor空間。
因爲老年代的特色是每次回收都只回收少許對象,通常使用的是標記-整理算法。
上面用到的複製算法,按照前面講的,按照空間1:1分配的,可是分代算法中不是這樣的,而是按照8:2 (4:1)的比例進行分配的,其中後面一塊又等分紅了兩塊,也就是8:1:1的比例,8爲新生代(Eden區),1分別爲兩塊等大小的Survivor區。
全部新建立的對象都是放在Eden區的,因此有不少的臨時變量,故每次大部分回收的垃圾都是在Eden區的,因此Eden區會分配那麼多的空間,那爲何要分兩塊Survivor區呢?
是由於,在進行一次coping算法回收時將Eden區中存活的對象複製到Survivor區,而後在進行一次回收時,Survivor區的存活對象沒地方存放了,由於Eden區每次都有新建立的對象存在。故在新建一塊Survivor B區,這時將Eden和Survivor A區存活的對象放在B區,而後清空Eden和Survivor A區。這樣就至關於A和B每次回收後都有一個是全新的也就是空的,就是爲了循環這種操做。