對象的結(jié)構(gòu)
一般來說,對象由頭(head)和域(field)兩個(gè)部分組成拆檬,如下圖所示
對象結(jié)構(gòu)
其中head主要包含了對象的大小浪汪,種類以及一些gc需要信息变汪。field主要用于存儲對象中可訪問的部分伤为,也就是我們平時(shí)看到的對象的方法變量之類的
對象的生與死
目前主要的對象判活算法有 可達(dá)性分析算法 和 引用計(jì)數(shù)算法
- 可達(dá)性分析算法通過從 GC Roots 開始向下搜索袱耽,如果一個(gè)對象沒有在引用鏈上存在時(shí)杀餐,則判定對象可以被回收
- 引用計(jì)數(shù)算法通過給對象添加一個(gè)引用計(jì)數(shù)器,通過引用計(jì)數(shù)判斷對象是否存活朱巨,由于引用計(jì)數(shù)算法無法解決循環(huán)引用的問題史翘,主流的Java虛擬機(jī)都沒有采用這種方法。但是由于其實(shí)現(xiàn)方便冀续,效率高的特點(diǎn)琼讽,可以作為一種輔助手段存在
對象的生活環(huán)境
就像人類的社會有資本主義和社會主義的劃分,對象的生活環(huán)境也不相同洪唐。目前常見的垃圾回收算法有 標(biāo)記清除算法(mark-sweep)钻蹬,標(biāo)記壓縮算法(mark-compact),復(fù)制算法(copying)
- mark-sweep分為 mark 和 sweep 兩個(gè)階段:首先標(biāo)記出所有需要回收的對象凭需,然后統(tǒng)一回收這部分對象问欠。
- mark-compact在標(biāo)記階段與mark-sweep相同桂敛,但是后續(xù)會將對象向堆的一端移動(dòng),并清除邊界外的所有對象溅潜。
- copying將可用內(nèi)存分成兩個(gè)部分,一塊內(nèi)存使用完了之后將活著的對象移動(dòng)到另一塊內(nèi)存薪伏,再把使用過的內(nèi)存一次清理掉滚澜。
時(shí)間開銷
- mark-sweep: mark階段與活對象的數(shù)量成正比,sweep階段與整堆大小成正比(不需要移動(dòng)對象嫁怀,開銷比compact猩杈琛)
- mark-compact: mark階段與活對象的數(shù)量成正比,compact階段與活對象的大小成正比
- copying: 與活對象成正比
空間開銷
- mark-sweep: 刑潦纭(產(chǎn)生碎片)
- mark-compact: 新苷小(不產(chǎn)生碎片)
- copying: 通常需要活對象的2倍大小(不產(chǎn)生碎片)
分配對象開銷
mark-sweep由于有內(nèi)存碎片的存在存捺,分配對象需要通過查詢當(dāng)前內(nèi)存使用情況槐沼,選擇一塊適合的內(nèi)存分配,因此mark-sweep在分配內(nèi)存的時(shí)候存在額外的時(shí)間開銷捌治。而mark-compact和copying分配對象不需要考慮這種情況
對象的輩分
一般情況下將Java堆分為 新生代岗钩,老年代
對象的分配優(yōu)先放在新生代,新生代在一段時(shí)間內(nèi)會有大量的臨時(shí)對象產(chǎn)生肖油,因此存活的對象比較少兼吓,比較適合copying算法。對象在經(jīng)過一定次數(shù)的copying gc之后會升級到老年代森枪。老年代一般采用mark-sweep和mark-compact算法视搏,正常情況下運(yùn)行的是mark-sweep,在內(nèi)存碎片達(dá)到一定程度的時(shí)候啟動(dòng)mark-compact县袱。大對象直接存放到老年代浑娜。
參考: