對象存活判定算法
引用計(jì)數(shù)算法
原理是每個(gè)對象都有一個(gè)引用計(jì)數(shù)器,當(dāng)被引用時(shí),計(jì)數(shù)器加1格侯,取消引用時(shí)計(jì)數(shù)器減1。計(jì)數(shù)器為0時(shí)表明該對象不再被其他對象引用企蹭,就可以回收。
弊端是當(dāng)出現(xiàn)循環(huán)引用時(shí)無法回收,導(dǎo)致內(nèi)存泄露。
可達(dá)性分析算法
原理是通過一系列成為GC ROOTS的對象作為根節(jié)點(diǎn)套像,開始向下搜索,所走過的路徑成為引用鏈终息,當(dāng)一個(gè)對象通過任何引用鏈都不可達(dá)時(shí),這個(gè)對象就會被回收贞让。
可以作為GC roots的對象包括:
- 虛擬機(jī)棧(棧幀中的本地變量表)中引用的對象周崭。
- 方法區(qū)中類靜態(tài)屬性引用的對象。
- 方法區(qū)中常量引用的對象
- 本地方法棧中JNI(即一般說的Native方法)引用的對象喳张。
JAVA中的引用
- 強(qiáng)引用
- 軟引用
- 弱引用
- 虛引用
對象的自我救贖
當(dāng)對象在可達(dá)性分析算法中通過任何引用鏈都不可達(dá)時(shí)续镇,該對象也不會立即被回收。只是相當(dāng)于被判死緩销部。真正執(zhí)行死刑分兩次標(biāo)記階段:當(dāng)對象不可達(dá)時(shí)摸航,被第一次標(biāo)記并且篩選,看該對象是否有必要執(zhí)行finalize方法舅桩。如果該對象沒有覆蓋finalize方法或者該對象的finalize方法已經(jīng)被執(zhí)行過酱虎,則該對象就沒有必要執(zhí)行finalize方法。如果該對象被判定為有必要執(zhí)行finalize方法擂涛,那么這個(gè)對象將被放入一個(gè)叫做F-Queue的隊(duì)列中读串,然后由一個(gè)虛擬機(jī)自動建立的低優(yōu)先級的finalizer線程去執(zhí)行。所謂的執(zhí)行只代表觸發(fā)這個(gè)方法撒妈,并不會等待方法執(zhí)行結(jié)束恢暖,這是因?yàn)槿绻粋€(gè)對象在finalize方法中執(zhí)行緩慢或者出現(xiàn)死循環(huán),則這個(gè)線程將會被阻塞狰右,F(xiàn)-Queue中的其他對象永遠(yuǎn)處于等待中杰捂,整個(gè)內(nèi)存回收系統(tǒng)會崩潰。finalize才能決定該對象最后的命運(yùn)棋蚌。如果在finalize方法中重新與引用鏈 中 的對象建立關(guān)聯(lián)嫁佳,譬如把自己賦值給某個(gè)類變量或者對象的成員變量挨队,在第二次標(biāo)記時(shí)該對象將被從F-Queue隊(duì)列中移除。剩下的對象將被真的回收脱拼。但是如果被移除的對象又一次被判死刑瞒瘸,則finalize方法也拯救不了它了,因?yàn)閒inalize方法只會被執(zhí)行一次熄浓。(這就好比一個(gè)女人被判了死刑情臭,但是執(zhí)行死刑前發(fā)現(xiàn)該犯人懷孕了,那就不會被執(zhí)行死刑了赌蔑。但是這免死金牌只能用一次俯在。)
垃圾收集算法
- 標(biāo)記-清除算法
是其他收集算法的基礎(chǔ)。缺點(diǎn)是標(biāo)記和清除階段效率都比較低娃惯,而且會導(dǎo)致內(nèi)存碎片問題跷乐。 - 復(fù)制算法
原理是把內(nèi)存分為大小相等的兩塊,每次分配只在其中一塊上進(jìn)行分配趾浅,當(dāng)這塊內(nèi)存用完的時(shí)候就將還存活的對象復(fù)制到另一塊中愕提,然后將這塊全部清理掉。這樣使得每次都是對整個(gè)半?yún)^(qū)進(jìn)行回收皿哨,而且也沒有碎片問題浅侨,只要移動堆頂指針,按順序分配內(nèi)存即可证膨。優(yōu)點(diǎn)是比較簡單如输,效率比較高。缺點(diǎn)是將可用內(nèi)存縮減為原來的一半了央勒,代價(jià)比較高不见,而且如果存活對象比較多,則復(fù)制操作就會比較多崔步,效率就會變低稳吮。年輕代的垃圾回收算法采用此算法。 - 標(biāo)記-整理算法
原理是標(biāo)記過程依然與“標(biāo)記-清理”算法中的標(biāo)記過程一樣井濒。只是在清理階段是將存活對象移動到一起盖高,然后將剩下的空間清理。 - 分代收集算法
垃圾收集器
- Serial收集器(年輕代采用)
它是個(gè)單線程的收集器眼虱。在進(jìn)行垃圾收集時(shí)必須暫停其他所有的工作線程喻奥。STOP THE WORLD。優(yōu)點(diǎn)是簡單高效捏悬。 - ParNew收集器(年輕代采用)
ParNew收集器是Serial收集器的多線程版本撞蚕。 - Parallel Scavenge收集器(年輕代采用)
也被稱為“吞吐量優(yōu)先收集器”。機(jī)制上也是多線程的过牙,與ParNew收集器一樣甥厦。但是它的關(guān)注點(diǎn)不是盡可能的縮短用戶線程等待時(shí)間纺铭,而是達(dá)到一個(gè)可控制吞吐量。另外Parallel Scavenge收集器有一個(gè)自適應(yīng)調(diào)節(jié)策略刀疙,即虛擬機(jī)會根據(jù)當(dāng)前系統(tǒng)的運(yùn)行情況收集性能監(jiān)控信息舶赔,然后動態(tài)的調(diào)整參數(shù)來提供合適的停頓時(shí)間或者提升最大的吞吐量。 - Serial Old收集器(老年代采用)
Serial Old收集器是Serial收集器的年老代版本谦秧。也是單線程的竟纳,但是使用“標(biāo)記-整理”算法。 - Parallel Old收集器(老年代采用)
它是Parallel Scavenge收集器的老年代版本疚鲤。使用多線程和“標(biāo)記-整理”算法锥累。 - CMS(Concurrent Mark Sweep)收集器
基于“標(biāo)記-清除”算法實(shí)現(xiàn)。目標(biāo)是停頓時(shí)間最短集歇,適合服務(wù)端應(yīng)用桶略。
運(yùn)作過程分四個(gè)步驟:
1、初始標(biāo)記诲宇。該階段只標(biāo)記GC ROOTS能直接關(guān)聯(lián)到的對象际歼。需要STOP THE WORLD。
2姑蓝、并發(fā)標(biāo)記蹬挺。該階段開始整個(gè)引用鏈的標(biāo)記過程,是和用戶線程并發(fā)執(zhí)行的它掂。
3、重新標(biāo)記溯泣。該階段是為了修正并發(fā)標(biāo)記階段因?yàn)橛脩舫绦虺掷m(xù)運(yùn)行而導(dǎo)致的變動虐秋。
4、并發(fā)清除垃沦。該階段也是和用戶線程并發(fā)執(zhí)行的客给。
該收集器優(yōu)點(diǎn):并發(fā)收集、低停頓肢簿。
缺點(diǎn):并發(fā)階段需要占用一部分線程靶剑,搶占CPU,所以勢必導(dǎo)致用戶線程的執(zhí)行變慢池充。無法處理浮動垃圾桩引。而且由于基于“標(biāo)記-清除”算法,所以會產(chǎn)生內(nèi)存碎片收夸。 - G1收集器
特點(diǎn):
1坑匠、并行與并發(fā)。
2卧惜、分代收集
3厘灼、空間整合
4夹纫、可預(yù)測的停頓
內(nèi)存分配與回收策略
- 對象優(yōu)先在Eden區(qū)分配
- 大對象直接在老年代分配。虛擬機(jī)提供了一個(gè)-XX:PretenureSizeThreshold參數(shù)來設(shè)置设凹。
- 長期存活的對象將進(jìn)入老年代舰讹。每個(gè)對象都有年齡計(jì)數(shù)器,虛擬機(jī)默認(rèn)設(shè)置的是15歲進(jìn)入老年代闪朱。-XX:MaxTenuringThreshold設(shè)置月匣。
- 動態(tài)對象年齡判定
如果在Survivor空間中相同年齡的所有對象大小的總和大于Survivor空間的一般,年齡大于或等于該年齡的對象就可以直接進(jìn)入老年代無須達(dá)到年齡监透。 - 空間分配擔(dān)保
在發(fā)生MinorGC之前桶错,虛擬機(jī)會檢查年老的最大可用的連續(xù)空間是否大于新生代所有對象總空間,如果大于胀蛮,則可以進(jìn)行MinorGC院刁;否則虛擬機(jī)會查看HandlePromotionFailure設(shè)置值是否允許擔(dān)保失敗,如果允許那么繼續(xù)檢查年老代最大可用的連續(xù)空間是否大于歷次晉升到老年代對象的平均大小粪狼,如果大于退腥,將嘗試進(jìn)行一次MinorGC,如果小于或者不允許擔(dān)保失敗再榄,則改為進(jìn)行FullGc狡刘。