一.判斷對(duì)象已死的方法
1.引用計(jì)數(shù)算法
引用時(shí)就加一包斑,引用失效時(shí)就減一
但是容易出現(xiàn)兩個(gè)對(duì)象互相引用的時(shí)候檐春,就可能無(wú)法回收了组橄。
2.可達(dá)性分析算法
GC Roots的幾種:
1).虛擬機(jī)棧中引用的對(duì)象
2).方法區(qū)中類(lèi)靜態(tài)屬性引用的對(duì)象
3).方法區(qū)中常量引用的對(duì)象
4).本地方法棧中引用的對(duì)象
3.引用的幾種類(lèi)型
強(qiáng)軟弱虛四種引用類(lèi)型
強(qiáng)引用:
只要強(qiáng)引用還存在,就不會(huì)被回收
軟引用:
在將要發(fā)生內(nèi)存溢出之前,會(huì)被回收掉的對(duì)象瓢省。
弱引用:
比軟引用更弱,只能生存到下次垃圾回收之前痊班。
虛引用:
只能在回收的時(shí)候收到一個(gè)系統(tǒng)通知勤婚,是最弱的一種引用。
4.對(duì)象的回收
被收集前的兩次標(biāo)記和對(duì)象的自我拯救
當(dāng)一個(gè)對(duì)象不可達(dá)時(shí)辩块,JVM會(huì)對(duì)其進(jìn)行一系列的判斷蛔六,首先判斷這個(gè)對(duì)象有沒(méi)有覆蓋finalize方法或者有沒(méi)有被JVM標(biāo)記過(guò),如果符合條件則直接回收废亭,如果沒(méi)有覆蓋finalize方法,或者被標(biāo)記過(guò)具钥,則進(jìn)行第一次標(biāo)記豆村,將對(duì)象放入F_QUEUE隊(duì)列當(dāng)中,然后等待JVM的第二次標(biāo)記骂删,JVM的第二次標(biāo)記則是判斷掌动,在等候的過(guò)程中,這個(gè)不可達(dá)的對(duì)象是否重新有了GC ROOT宁玫,如果此時(shí)它變成了一個(gè)可達(dá)對(duì)象粗恢,那么它就完成了一次自我拯救,可以不用被回收欧瘪,如果依舊不可達(dá)眷射,就進(jìn)行二次標(biāo)記直接回收。
但是這種自我拯救只有一次機(jī)會(huì)佛掖。
5.回收方法區(qū)
永生代主要回收兩部分:廢棄常量妖碉,和無(wú)用的類(lèi)
常量:如果沒(méi)有任何一個(gè)string對(duì)象引用這個(gè)常量,就判定為廢棄常量芥被。
類(lèi):滿(mǎn)足以下三個(gè)條件才可以被回收
1).該類(lèi)的所有實(shí)例都被回收了
2).加載該類(lèi)的classload都被回收了
3).該類(lèi)對(duì)應(yīng)的對(duì)象都沒(méi)有被引用了
二.垃圾回收算法
1.分代收集
一般分為新生代收集和老年代收集欧宜。
現(xiàn)在一般的收集方法有:minor GC,major GC 拴魄,mixed GC(G1收集器)和full GC冗茸,minor GC針對(duì)一些朝生夕滅的對(duì)象,而major GC收集一些難以回收的對(duì)象匹中。分代收集可以兼顧時(shí)間開(kāi)銷(xiāo)和內(nèi)存的有效利用夏漱。
分代收集可能產(chǎn)生的問(wèn)題---跨代收集
有可能新生代和老年代又互相引用的對(duì)象,不能在收集新生代的時(shí)候掃描整個(gè)老年代职员,解決辦法是麻蹋,建立一個(gè)記憶集,Remeberd set焊切,這個(gè)結(jié)構(gòu)可以把老年代分成若干個(gè)小塊扮授,表示出老年代的那一部分存在跨代引用芳室,收集新生代的時(shí)候,只有包含跨代引用的區(qū)域才會(huì)被掃描刹勃。
2.標(biāo)記清除(Mark-Sweep)
標(biāo)記以后進(jìn)行統(tǒng)一回收堪侯,但是容易產(chǎn)生大量不連續(xù)內(nèi)存碎片
3.標(biāo)記-復(fù)制算法
把內(nèi)存分為一塊較大的Eden和兩塊較小的Survivor,每次使用eden和其中一塊survior荔仁,回收時(shí)將依然存活的對(duì)象復(fù)制到另一塊survivor上伍宦,然后將eden和使用過(guò)的survivor消除,反復(fù)進(jìn)行這個(gè)操作乏梁。
4.標(biāo)記-整理算法
將存活的對(duì)象統(tǒng)一移動(dòng)到一部分次洼,然后再直接清理掉邊界以外的內(nèi)存。
但是移動(dòng)并且更新所有引用關(guān)系負(fù)重很大遇骑,并且還要暫停所有用戶(hù)線程“stop the world”卖毁,所以停頓時(shí)間長(zhǎng)就是一個(gè)缺點(diǎn)。
二.hotspot算法的細(xì)節(jié)實(shí)現(xiàn)(安全點(diǎn)OOPmap)
1.oopmap
所有的垃圾收集器都會(huì)面臨查找整個(gè)gcroot的關(guān)系落萎,并且進(jìn)行時(shí)間停頓的問(wèn)題亥啦,
為了解決這個(gè)問(wèn)題,JVM提供了一個(gè)準(zhǔn)確式收集的方案练链,即使用一組OOPMAP的數(shù)據(jù)結(jié)構(gòu)翔脱,當(dāng)類(lèi)加載完成以后,可以記錄下一個(gè)對(duì)象什么偏移量是什么數(shù)據(jù)結(jié)構(gòu)媒鼓,就會(huì)在特定的位置記錄下棧里和寄存器里哪些位置是引用届吁。這樣就不需要從gcroot一點(diǎn)點(diǎn)查找了。但是如果每個(gè)指令都建立oopmap會(huì)產(chǎn)生大量的內(nèi)存開(kāi)銷(xiāo)隶糕,所以只在指定的位置(安全點(diǎn))來(lái)建立瓷产。
2.安全點(diǎn)
一般安全點(diǎn)的位置產(chǎn)生在指令序列容易出現(xiàn)復(fù)用的地方,例如方法調(diào)用枚驻,循環(huán)跳轉(zhuǎn)濒旦,異常處理等等。
而且對(duì)于安全點(diǎn)的使用再登,一般是讓垃圾收集是讓所有的線程都能跑到最近的安全點(diǎn)尔邓,在這有兩種方案,一種是主動(dòng)式中斷锉矢,一種是搶先式中斷梯嗽。
主動(dòng)中斷是設(shè)立一個(gè)標(biāo)志位,一直不停的去輪訓(xùn)沽损,當(dāng)發(fā)現(xiàn)中斷的標(biāo)志位變?yōu)檎娴平冢妥尞?dāng)前線程跑到最近的一個(gè)安全點(diǎn)中斷。
搶先式中斷則是在中斷以后判斷是否在安全點(diǎn),如果不在的話就重新啟動(dòng)該線程炎疆,跑到最近的一個(gè)安全點(diǎn)在中斷卡骂。
3.安全區(qū)域
程序發(fā)生異常時(shí)候,可能無(wú)法準(zhǔn)確走到安全點(diǎn)形入,這事可以走到安全區(qū)域全跨,安全區(qū)域一般是引用關(guān)系不會(huì)發(fā)生變化的一個(gè)區(qū)域,相當(dāng)于擴(kuò)展的安全點(diǎn)亿遂。
4.記憶集和卡表
解決跨代引用浓若。
5.并發(fā)的可達(dá)性分析
如何降低stop the world 的時(shí)間:三色標(biāo)記法
白色;尚未被垃圾收集器訪問(wèn)過(guò)蛇数,如果分析結(jié)束以后還是白色挪钓,就說(shuō)明gcroot不可達(dá),可以被回收
黑色耳舅;已經(jīng)被訪問(wèn)過(guò)诵原,說(shuō)明有對(duì)象引用,安全存活
灰色挽放;訪問(wèn)過(guò),但是至少存在一個(gè)引用還沒(méi)有被掃描
三.幾種經(jīng)典的垃圾收集器
1.Serial收集器
新生代收集器:?jiǎn)尉€程蔓纠,速度很快辑畦,但是時(shí)間停頓時(shí)間很長(zhǎng)
2.Serial-old收集器
老年代收集器,特點(diǎn)同serial
3.Parnew收集器
serial的多線程并行的版本
4.Parallel Old收集器
Parnew的老年代收集器版本
5.Parallel Scanvage收集器
新生代收集器腿倚,基于標(biāo)記復(fù)制算法纯出,看重吞吐量。
吞吐量是用戶(hù)運(yùn)行代碼時(shí)間除以用戶(hù)運(yùn)行代碼時(shí)間加上垃圾收集的時(shí)間
6.CMS收集器
特點(diǎn)是工作線程可以和垃圾收集線程同時(shí)進(jìn)行敷燎,并且基于標(biāo)記清除算法
優(yōu)點(diǎn):并行暂筝,且停頓時(shí)間短
缺點(diǎn):容易產(chǎn)生大量?jī)?nèi)存碎片,和浮動(dòng)垃圾(當(dāng)工作進(jìn)程和收集進(jìn)程同時(shí)進(jìn)行時(shí)產(chǎn)生的無(wú)法在本次被收集的垃圾)
7.G1收集器
基于region收集硬贯,而且無(wú)需區(qū)分新生代和老年代焕襟,而是面向整個(gè)gc堆,尋找垃圾最多的區(qū)域進(jìn)行收集饭豹。
這樣也可以達(dá)到一個(gè)可預(yù)測(cè)停頓時(shí)間的目的鸵赖。并且因?yàn)槭菢?biāo)記整理算法,所以?xún)?nèi)存碎片也很少拄衰。
8.ZGC和shenandoah收集器
低延遲收集器它褪。
ZGC:染色指針等
四.內(nèi)存分配策略
1.對(duì)象優(yōu)先在Eden分配
2.大對(duì)象直接進(jìn)入老年代
-XX:PretentureSizeThreshold參數(shù)指定超過(guò)多大可以直接進(jìn)入老年代
3.長(zhǎng)期存活的對(duì)象進(jìn)入老年代
對(duì)象頭中有一個(gè)對(duì)象年齡計(jì)數(shù)器,超過(guò)
-XX:MAXTenuringThreshold=1
的數(shù)字時(shí)翘悉,則會(huì)直接進(jìn)入老年代茫打,此參數(shù)默認(rèn)為15
4.動(dòng)態(tài)年齡判定
當(dāng)新生代內(nèi)存不夠,雖然沒(méi)有達(dá)到3中設(shè)定的參數(shù)值,但是也可以直接進(jìn)入老年代
5.空間分配擔(dān)保
當(dāng)新生代內(nèi)存不夠老赤,則需要進(jìn)入老年代轮洋,所以需要minor GC前必須保證老年代最大可用空間大于新生代所有對(duì)象大小的總和,jvm可以采用歷史平均值來(lái)判定诗越,不超過(guò)砖瞧,從而進(jìn)行一次minorGC,但是如果超過(guò)了嚷狞,就需要full gc了块促,所以使用平均值判定是存在風(fēng)險(xiǎn)的,但是可以通過(guò)以下參數(shù)
-XX:handlePromotionFailure設(shè)置不允許冒險(xiǎn)