在現(xiàn)行的垃圾回收算法中主要有以下幾種:
1.標(biāo)記-清除算法
標(biāo)記-清除算法是最基本的算法,后續(xù)的算法都是在這個(gè)基礎(chǔ)上對(duì)其不足進(jìn)行改進(jìn)而得到的。
這個(gè)算法主要分為兩步:1 標(biāo)記所有活動(dòng)的對(duì)象;2? 清除已經(jīng)死亡的對(duì)象(標(biāo)記了的是活動(dòng)的對(duì)象,未標(biāo)記的就是可清除的對(duì)象)
第一步 :標(biāo)記所有活動(dòng)的對(duì)象? (另一種說(shuō)法是標(biāo)記所有需要回收的對(duì)象,無(wú)論是哪一種,其原理是一致的)
標(biāo)記使用的是 深度優(yōu)先遍歷 (根 -左-右),原因是內(nèi)存使用量要比 廣度優(yōu)先遍歷 (層次遍歷)要小。
具體實(shí)現(xiàn):首先要標(biāo)記根直接引用的對(duì)象,然后進(jìn)行遞歸,偽代碼就是:
mark(obj){
? ? ? ? if(obj.mark == FALSE)//如果沒(méi)有標(biāo)記
? ? ? ? ? ? ? obj.mark =TRUE //則設(shè)置為標(biāo)記
? ? ? ? for(child : children(obj))//遞歸處理子對(duì)象
? ? ? ? ? ? ? mark(*child)
}
判斷對(duì)象是否存活用的是前面介紹過(guò)的 對(duì)象的可達(dá)性分析
第二步:清除所有沒(méi)有標(biāo)記的對(duì)象
在這一步,我們遍歷整個(gè)java堆,按順序一個(gè)一個(gè)的遍歷對(duì)象的標(biāo)記標(biāo)志位
1.設(shè)置了標(biāo)志位的,表示是存活的對(duì)象,將標(biāo)志位設(shè)為false,為下一次GC 的標(biāo)記 做準(zhǔn)備
2.沒(méi)有設(shè)置標(biāo)志位的,表示當(dāng)前對(duì)象已經(jīng)可以回收

該回收算法的優(yōu)缺點(diǎn)
1.優(yōu)點(diǎn):算法簡(jiǎn)單,實(shí)現(xiàn)容易
2 缺點(diǎn):一個(gè)是效率不高。二個(gè)是內(nèi)存碎片化。在標(biāo)記清除之后會(huì)產(chǎn)生大量的不連續(xù)的內(nèi)存碎片,空間碎片太多會(huì)導(dǎo)致在需要分配較大的對(duì)象時(shí),無(wú)法找到足夠連續(xù)的內(nèi)存而不得不提前觸發(fā)下一次GC。
3.標(biāo)記-清除 算法使用的時(shí)空閑鏈表
后面的算法均時(shí)根據(jù)該算法的缺點(diǎn)進(jìn)行改進(jìn)而衍生出來(lái)的
2.復(fù)制算法
原理:將可用內(nèi)存分為大小相等的兩塊,每次使用其中一塊,當(dāng)使用的那一塊內(nèi)存用完后,將存活的對(duì)象復(fù)制到另一塊上,然后一次性清理掉用完的那塊空間,如此往復(fù)。
這樣設(shè)計(jì)的目的時(shí)為了 解決效率問(wèn)題,實(shí)現(xiàn)了傳統(tǒng)意義上的空間換時(shí)間。
復(fù)制算法執(zhí)行時(shí)分為三個(gè)重要步驟
1.標(biāo)記存活對(duì)象
2.拷貝存活對(duì)象(已經(jīng)標(biāo)記的對(duì)象)到新的內(nèi)存區(qū)域,并更新對(duì)象指針。
3.一次性清理已使用的內(nèi)存空間

復(fù)制算法的優(yōu)點(diǎn)
優(yōu)點(diǎn) :實(shí)現(xiàn)簡(jiǎn)單,運(yùn)行高效,不會(huì)發(fā)生內(nèi)存碎片化(移動(dòng)指針,按序分配內(nèi)存)
缺點(diǎn):內(nèi)存使用率低下(將內(nèi)存一分為二,每一次只有一半的內(nèi)存可用),存活對(duì)象較多時(shí),效率同樣不高
由于最原始的算法內(nèi)存使用率太低,后來(lái)的商業(yè)虛擬機(jī)在這基礎(chǔ)上有一定的改進(jìn)。
在新生代中的對(duì)象98%的對(duì)象是“朝生夕死”,所以并不需要以1:1 的比例來(lái)分配 from 與 To 的空間,而是將內(nèi)存分為一塊較大的Eden空間跟兩塊較小的 Survivor空間(HotSpot中默認(rèn)的時(shí)8:1:1),每次使用的是Eden與其中的一塊Survivor空間。當(dāng)回收時(shí),將存活的對(duì)象復(fù)制到另一塊Survivor空間上,最后清理掉Eden與survivor空間,這樣能使用的內(nèi)存空間就大大提高了。
如果剩下的Survivor空間不夠存放存活的對(duì)象,就需要依賴其他內(nèi)存來(lái)進(jìn)行分配擔(dān)保了,這些對(duì)象會(huì)直接通過(guò)分配擔(dān)保機(jī)制直接進(jìn)入老年代。
3.標(biāo)記-整理算法 (又稱標(biāo)記-壓縮算法)
標(biāo)記-整理算法時(shí)在標(biāo)記-清除算法上的一種改進(jìn)。整理不會(huì)改變對(duì)象排列的順序,只會(huì)縮小他們之間的間隙,把對(duì)象聚集到堆的一端。
標(biāo)記階段與前面的分析沒(méi)有什么區(qū)別,整理壓縮主要有以下三個(gè)步驟:
1.設(shè)定forwarding 指針
2.更新指針
3.移動(dòng)對(duì)象

標(biāo)記-整理算法的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):java堆的利用得到進(jìn)一步的提高
缺點(diǎn):整理是一個(gè)移動(dòng)對(duì)象的過(guò)程,伴隨著對(duì)象的移動(dòng)以及指針的修改,這也是一筆不小的開銷
4.分代收集算法
這是現(xiàn)在主流的商業(yè)虛擬機(jī)采用的垃圾回收算法,其主要思想是將Java堆分為 新生代 與 老年代。
對(duì)新生代采用一般采用復(fù)制算法(大量的對(duì)象死亡,回收效率比較高),對(duì)老年代就必須使用標(biāo)記-清除或者標(biāo)記-整理算法來(lái)進(jìn)行回收
優(yōu)缺點(diǎn)
優(yōu)點(diǎn):效率明顯提升
缺點(diǎn):新生代GC所花費(fèi)的時(shí)間會(huì)增多,老年代GC會(huì)頻繁運(yùn)行。
現(xiàn)在常使用的垃圾收集器有如下幾種

1.serial收集器? ? (新生代 單線程? 復(fù)制算法)
jdk1.3.1之前是新生代收集的唯一選擇
這是以一個(gè)單線程的收集器,它工作時(shí)會(huì)暫停其他所有的工作線程 也就是著名的 Stop- The -World

優(yōu)點(diǎn):由于是單線程,所以沒(méi)有線程之間的切換開銷
缺點(diǎn):在其工作時(shí)會(huì)停止所有其他工作線程
2.ParNew 收集器? (serial的多線程版本) 新生代? 多線程? 復(fù)制算法

在單CPU的環(huán)境下,其效率還不如Serial收集器
3.Parallel Scanvenge 收集器? (新生代 多線程? 復(fù)制算法)
這個(gè)收集器關(guān)注的不是系統(tǒng)停頓的時(shí)間,而是達(dá)到一個(gè)可以控制的吞吐量
4.Serial Old收集器 (老年代 單線程? 標(biāo)記-整理算法)
5.Paralle Old 收集器 (老年代 多線程 標(biāo)記-整理算法)
關(guān)注點(diǎn):吞吐量
6.CMS收集器 Concurrent Mark Sweep(老年代 多線程 標(biāo)記-清除算法)
關(guān)注點(diǎn):獲取最短回收停頓時(shí)間為目標(biāo)的收集器

CMS收集器工作流程分為四個(gè)步驟
1.初始標(biāo)記//stop the world 標(biāo)記以下GC Roots能關(guān)聯(lián)到的對(duì)象
2.并發(fā)標(biāo)記// 標(biāo)記GC Roots之后的對(duì)象
3.重新標(biāo)記//stop the world 修正并發(fā)期間用戶程序繼續(xù)運(yùn)行產(chǎn)生變動(dòng)的那一部分對(duì)象的標(biāo)記記錄
4.并發(fā)清除
這是一款真正意義上的 并發(fā) 垃圾收集器
缺點(diǎn)
1.對(duì)CPU資源非常敏感
2.無(wú)法處理浮動(dòng)垃圾(垃圾收集的過(guò)程中,應(yīng)用程序運(yùn)行產(chǎn)生的其他垃圾)
3.因?yàn)闀r(shí)基于標(biāo)記-清除算法,所以依舊會(huì)產(chǎn)生大量的內(nèi)存碎片
7.科技的最前沿 G1收集器
G1的優(yōu)點(diǎn)有以下幾點(diǎn):
1.并行與并發(fā)
2.分代收集
3.基于標(biāo)記-整理算法,會(huì)對(duì)空間進(jìn)行進(jìn)一步的整合
4.Stop-The-World 的時(shí)間可以預(yù)測(cè)