判斷對象是否已死:
- 引用計數(shù)法(很難解決對象之間相互循環(huán)引用的問題)
- 可達(dá)性分析算法
- 可作為GC Roots的對象包括:
① 虛擬機(jī)棧中引用的對象
② 方法去中類靜態(tài)屬性引用的對象
③ 方法區(qū)中常量引用的對象
④ 本地方法棧中JNI(Native方法)引用的對象
引用
- 強(qiáng)引用
- 軟引用
- 弱引用
- 虛引用
回收區(qū)域
1. 方法區(qū):回收性價比低
2. 堆(主要回收區(qū)域):
- 新生代:Minor GC(復(fù)制算法)
- 老年代:Major GC/Full GC(標(biāo)記—整理算法)
- 永久代:廢棄常量和無用類
無用類:
① 該類的所有實(shí)例已被回收
② 加載該類的ClassLoader已被回收
③ 該類對應(yīng)的java.lang.Class對象沒有在任何地方被引用雀费,無法在任何地方通過反射訪問該類內(nèi)存的永久保存區(qū)域,主要存放Class和Meta(元數(shù)據(jù))的信息,Class在被加載的時候被放入永久區(qū)域. 它和存放實(shí)例的區(qū)域不同,GC不會在主程序運(yùn)行期對永久區(qū)域進(jìn)行清理罐农。所以這也導(dǎo)致了永久代的區(qū)域會隨著加載的Class的增多而脹滿莫秆,最終拋出Out of Memory異常间雀。
在Java8中,永久代已經(jīng)被移除镊屎,被一個稱為“元數(shù)據(jù)區(qū)”(元空間)的區(qū)域所取代惹挟。
不過元空間與永久代之間最大的區(qū)別在于:元空間并不在虛擬機(jī)中,而是使用本地內(nèi)存缝驳。因此连锯,默認(rèn)情況下,元空間的大小僅受本地內(nèi)存限制用狱。類的元數(shù)據(jù)放入 native memory, 字符串池和類的靜態(tài)變量放入java堆中. 這樣可以加載多少類的元數(shù)據(jù)就不再由MaxPermSize控制, 而由系統(tǒng)的實(shí)際可用空間來控制.
采用元空間而不用永久代的幾點(diǎn)原因:
1运怖、為了解決永久代的Out of Memory問題,元數(shù)據(jù)和class對象存在永久代中夏伊,容易出現(xiàn)性能問題和內(nèi)存溢出摇展。
2、類及方法的信息等比較難確定其大小溺忧,因此對于永久代的大小指定比較困難咏连,太小容易出現(xiàn)永久代溢出,太大則容易導(dǎo)致老年代溢出(因?yàn)槎芽臻g有限鲁森,此消彼長)捻勉。
3、永久代會為 GC 帶來不必要的復(fù)雜度刀森,并且回收效率偏低踱启。
4、Oracle 可能會將HotSpot 與 JRockit 合二為一。
垃圾收集算法
1. 標(biāo)記—清除算法(最基本)
2. 復(fù)制算法(新生代)
- 新生代分為:Eden和兩個Survivor大小比例是8:1埠偿,回收時透罢,將Eden和survivor中還存活的對象一次性的復(fù)制到另一個Survivor空間中 ,同時把這些對象的年齡+1(默認(rèn)情況下15歲就直接送到老年代了)冠蒋,最后清理掉Eden和剛才用過的Survivor空間羽圃。
- 如果Surviovr的空間不夠,需要依賴其他內(nèi)存(老年代)進(jìn)行分配擔(dān)保(虛擬機(jī)回檢查老年代最大可用的連續(xù)空間是否大于新生代所有對象的總空間)抖剿,這些對象直接通過分配擔(dān)保機(jī)制進(jìn)入老年代朽寞。(正常的需要Age達(dá)到15才可以進(jìn)入老年代),如果擔(dān)保失敗斩郎,且不允許脑融,則老年代需要進(jìn)行一次Full GC。
3. 標(biāo)記—整理算法(老年代)
垃圾收集器
內(nèi)存分配
- 對象優(yōu)先在Eden分配
- 大對象直接進(jìn)入老年代(大對象指很長的字符串以及數(shù)組)
- 長期存活的對象進(jìn)入老年代
- 虛擬機(jī)給每個對象一個對象年齡(Age)計數(shù)器缩宜。對象每經(jīng)過一次Minor GC Age就加一肘迎。(默認(rèn)是15歲就會進(jìn)入老年代)
- 如果Survivor中相同年齡的所有對象的總和大于空間的一半,則年齡大于或等于該年齡的對象都可以直接進(jìn)入老年代锻煌,無須等到要求的年齡妓布。