一、四種引用方式1.1 強(qiáng)引用1.2 軟引用(SoftReference)1.3 弱引用(WeakReference)1.4 虛引用(PhantomReference)
二、如何判斷對(duì)象是垃圾2.1 引用計(jì)數(shù)法2.2 根可達(dá)性分析
三、垃圾回收算法3.1 標(biāo)記-清除(mark-sweep)3.2 標(biāo)記-整理(mark-compact)3.3 標(biāo)記-復(fù)制(mark-copy)
四、垃圾收集器4.1 分類(lèi)及特點(diǎn)簡(jiǎn)述4.1.1 串行4.1.2 吞吐量?jī)?yōu)先4.1.3 響應(yīng)時(shí)間優(yōu)先4.2 串行垃圾回收器詳述4.2.1 Serial4.2.2 Serial-Old4.2.3 流程圖4.3 吞吐量?jī)?yōu)先垃圾回收器詳述4.3.1 JVM相關(guān)參數(shù)4.3.2 流程圖4.4、響應(yīng)時(shí)間優(yōu)先垃圾回收器詳述4.4.1 JVM相關(guān)參數(shù)4.4.2 流程圖4.3.3 CMS的特點(diǎn)
五、G1垃圾回收器5.1 相關(guān)JVM參數(shù)5.2 特點(diǎn)5.3 G1新生代垃圾回收5.4 G1老年代垃圾回收
一、四種引用方式
1.1 強(qiáng)引用
只有所有 GC Roots對(duì)象都不通過(guò)【強(qiáng)引用】引用該對(duì)象,該對(duì)象才可以被回收。
1.2 軟引用(SoftReference)
- 僅有軟引用引用該對(duì)象時(shí),在垃圾回收后,若內(nèi)存仍不足時(shí)再次發(fā)出的垃圾回收,回收軟引用對(duì)象
- 可以配合引用隊(duì)列來(lái)釋放軟引用自身
1.3 弱引用(WeakReference)
- 僅有弱引用引用該對(duì)象時(shí),每次發(fā)生垃圾回收的時(shí)候,無(wú)論內(nèi)存是否充足都會(huì)回收掉這部分對(duì)象
- 可以配合引用隊(duì)列來(lái)釋放軟引用自身
1.4 虛引用(PhantomReference)
- 必須配合引用隊(duì)列來(lái)使用,主要配合ByteBuffer的使用,被引用對(duì)象回收時(shí),會(huì)將虛引用存入隊(duì)列,由Reference Handler線(xiàn)程調(diào)用虛引用相關(guān)方法釋放直接內(nèi)存
二、如何判斷對(duì)象是垃圾
2.1 引用計(jì)數(shù)法
某個(gè)對(duì)象只要有一處引用關(guān)系,該對(duì)象的引用次數(shù)就加1,如果一個(gè)對(duì)象的引用次數(shù)為0,則說(shuō)明該對(duì)象是垃圾。
優(yōu)勢(shì):實(shí)現(xiàn)簡(jiǎn)單,效率較高
弊端:如果有一對(duì)對(duì)象之間形成了相互引用,但是這兩個(gè)對(duì)象都已經(jīng)沒(méi)有被其它對(duì)象所引用了,正常情況下,這一對(duì)對(duì)象應(yīng)該被作為垃圾回收掉,但是因?yàn)樾纬闪讼嗷ヒ脤?dǎo)致無(wú)法被回收。
2.2 根可達(dá)性分析
通過(guò)GC Root對(duì)象開(kāi)始向下尋找,尋找不到的對(duì)象即說(shuō)明沒(méi)有被引用,那么這些沒(méi)有被引用的對(duì)象被認(rèn)定為垃圾。
目前,如下對(duì)象可以作為GC Root對(duì)象:
三、垃圾回收算法
根據(jù)前面的描述,知道了哪些對(duì)象是垃圾需要被回收,那么回收是按照什么樣的算法呢?
3.1 標(biāo)記-清除(mark-sweep)
很好理解,即在GC的放生時(shí)候,先對(duì)所有對(duì)象進(jìn)行根可達(dá)性分析,借此標(biāo)記所有的垃圾對(duì)象;所有對(duì)象標(biāo)記完畢之后會(huì)進(jìn)行清理操作。
因此,總體來(lái)說(shuō),就是先標(biāo)記再清除。
弊端;標(biāo)記清除之后會(huì)產(chǎn)生大量不連續(xù)的內(nèi)存碎片,碎片太多可能會(huì)導(dǎo)致程序運(yùn)行過(guò)程中需要分配較大對(duì)象時(shí),無(wú)法滿(mǎn)足分配要求導(dǎo)致GC操作。
3.2 標(biāo)記-整理(mark-compact)
該回收算法操作過(guò)程基本等同于標(biāo)記-清除算法只不過(guò),第二步有點(diǎn)區(qū)別,該種方式會(huì)在清除的過(guò)程中進(jìn)行整理操作,這是最大的不同。
優(yōu)勢(shì):最終不會(huì)出現(xiàn)若干空間碎片而導(dǎo)致的空間浪費(fèi)。
弊端:在整理過(guò)程中帶來(lái)的計(jì)算不可小覷。
3.3 標(biāo)記-復(fù)制(mark-copy)
該種方式與前兩種有較大的區(qū)別:
該種方式會(huì)將存儲(chǔ)區(qū)分成兩個(gè)部分,分別為From、To,其中From區(qū)域中可能存在著對(duì)象,而To區(qū)域始終為空,用做下一次接受數(shù)據(jù)做準(zhǔn)備。
分別有兩個(gè)指針指向這兩個(gè)區(qū)域:From-Pointer、To-Pointer,
優(yōu)點(diǎn):這種算法非常適合早生夕死的對(duì)象
缺點(diǎn):始終有一塊內(nèi)存區(qū)域是未使用的,造成空間的浪費(fèi)。
四、垃圾收集器
垃圾收集器,就是實(shí)現(xiàn)了上述三種垃圾回收算法的具體實(shí)現(xiàn)
在Java中不同的“代”所保存的對(duì)象特點(diǎn)都不一樣,因此Java在垃圾回收的選擇上并沒(méi)有偏愛(ài)一種,只采用一種算法方式,而是根據(jù)不同“代”對(duì)象的特點(diǎn),采取不同的垃圾回收器(垃圾回收算法)。
4.1 分類(lèi)及特點(diǎn)簡(jiǎn)述
4.1 串行
特點(diǎn):
- 單線(xiàn)程
- 堆內(nèi)存小,適合于個(gè)人電腦
4.2 吞吐量?jī)?yōu)先
特點(diǎn):
- 多線(xiàn)程
- 堆內(nèi)存較大,適合多核CPU
- 讓單位時(shí)間內(nèi),STW的時(shí)間最短,即一段時(shí)間中,垃圾回收的時(shí)間與總運(yùn)行時(shí)間的占比,占比越小越好,說(shuō)明大多數(shù)時(shí)間都在處代碼邏輯
4.3 響應(yīng)時(shí)間優(yōu)先
特點(diǎn):
- 多線(xiàn)程
- 堆內(nèi)存較大,適合多核CPU
- 盡可能讓單次STW時(shí)間最短,只是單單的追求每次垃圾回收時(shí)間短即可,并不在意一段時(shí)間內(nèi)發(fā)生了多少次垃圾回收。
4.2 串行垃圾回收器詳述
JVM開(kāi)關(guān):-XX:+UseSerialGC = Serial + SerialOld
4.2.1 Serial
- 工作在新生代
- 采用復(fù)制算法
- 單線(xiàn)程
4.2.2 Serial-Old
- 老年代
- 采用標(biāo)記-整理算法
- 單線(xiàn)程
4.2.3 流程圖
4.3 吞吐量?jī)?yōu)先垃圾回收器詳述
JDK1.8默認(rèn)開(kāi)啟的,使用的算法本身與Serial是一致的,只是處理線(xiàn)程不一樣而已。
4.3.1 JVM相關(guān)參數(shù)
- -XX+UseParallelGC
- 工作在新生代
- 復(fù)制算法
- -XX+UseParallelOldGC
- 工作在老年代
- 標(biāo)記-整理算法
- -XX:+UseAdaptiveSizePolicy
- 動(dòng)態(tài)調(diào)整Eden與Survivor的比例
- -XX:GCTimeRatio=ratio(默認(rèn)為99)
- 占比 = 1/(1+radio)
- 表示希望在當(dāng)前運(yùn)行總時(shí)間中,GC的時(shí)間與總時(shí)間的占比小于等于上面的公式值。
- -XX:MaxGCPauseMills=ms(默認(rèn)200ms)
- 單次垃圾回收的時(shí)間
- -XX:ParallelGCThread=n
- 指定并行的垃圾處理線(xiàn)程數(shù),默認(rèn)為CPU核數(shù)
- 因此在垃圾回收的過(guò)程中可能會(huì)導(dǎo)致CPU一下子跑滿(mǎn)
4.3.2 流程圖
4.4、響應(yīng)時(shí)間優(yōu)先垃圾回收器詳述
4.4.1 JVM相關(guān)參數(shù)
- -XX:+UseParNewGC
- 工作在新生代
- -XX:+UseConcMarkSweepGC
- 工作在老年代,若垃圾回收失敗時(shí),則會(huì)退回到SerialOld垃圾回收。
- 采用標(biāo)記清除算法;
- 可以并發(fā)執(zhí)行,即在某些垃圾回收階段,垃圾回收線(xiàn)程可以與用戶(hù)線(xiàn)程一起執(zhí)行。
- -XX:ConGCThread=n
- 指定在并發(fā)收集的過(guò)程中,可以使用n個(gè)線(xiàn)程處理垃圾回收
- -XX:CMSInitiationOccupancyFraction=precent
- 在下面的分析中,會(huì)介紹到浮動(dòng)垃圾的概念,因此為了更加及時(shí)的清除浮浮動(dòng)垃圾,在老年代的空間占用達(dá)到了Precent的時(shí)候,就會(huì)觸發(fā)老年代的垃圾回收。
- -XX:+CMSScavengeBeforeRemark
- 因?yàn)槔夏甏腃MS涉及到重新標(biāo)記,重新標(biāo)記就是在判斷得到的垃圾對(duì)象是否又被重新引用。那么CMS會(huì)從新生代開(kāi)始,使用根可達(dá)性分析(因?yàn)楦蛇_(dá)性分析是不可逆的,也就是說(shuō)無(wú)法通過(guò)某個(gè)對(duì)象直接查看其是否被引用,就好像二叉查找樹(shù)一樣,必須先從根對(duì)象開(kāi)始往下尋找,看是否能找到該對(duì)象),而新生代中的對(duì)象較多,一個(gè)一個(gè)的從新生代對(duì)象進(jìn)行更可達(dá)性分析,勢(shì)必會(huì)拖慢響應(yīng)分析,因此在重新標(biāo)記之前,若改參數(shù)開(kāi)關(guān)已打開(kāi),會(huì)先進(jìn)行一次新生代的垃圾回收。
- -XX:ParallelGCThreads=n
- 指定并行的垃圾處理線(xiàn)程數(shù),默認(rèn)為CPU核數(shù)。
4.4.2 流程圖
上圖是:CMS垃圾回收器在老年代GC的工作流程圖:
4.3.3 CMS的特點(diǎn)
五、G1垃圾回收器
5.1 相關(guān)JVM參數(shù)
- -XX:UseG1GC
- 開(kāi)啟使用G1垃圾回收器
- -XX:G1HeapRegionSize=n(默認(rèn)是2048)
- 指定整個(gè)堆被劃分成N個(gè)Region,因此每個(gè)Region的大小為堆空間 / N,但是有一條硬性規(guī)定,即每個(gè)Region的大小必須是 2 的整數(shù)倍。
- 兩個(gè)初始Region數(shù)公式:
- 新生代的Region個(gè)數(shù) = 5% * N
- 老年代的Region個(gè)數(shù) = 95% * N
- 而對(duì)于新生代而言,在以往,新生代中進(jìn)一步被劃分為Eden區(qū)、Survivor(From、To)區(qū),且三者的比值依然為:8:1:1,這樣的劃分在G1中同樣的適用,只不過(guò)這樣的劃分不會(huì)出現(xiàn)在同一個(gè)Region中,而是Eden在某個(gè)獨(dú)立的新生代Region中,F(xiàn)rom、To都各占一個(gè)獨(dú)立的Region。
- -XX:InitaingHeapOccupancyPercent=45%
- 老年代的Region個(gè)數(shù)達(dá)到n%,即會(huì)觸發(fā)老年代垃圾回收。
- –XX:G1MixedGCuntTarget=n
- 在混合模式下的垃圾回收,在并發(fā)清理階段分為n次進(jìn)行
- -XX:MaxGCPauseMillis=ms
- 指定的垃圾回收最長(zhǎng)時(shí)間,如果時(shí)間很短,G1就只會(huì)回收那些回收價(jià)值最高的Region,這是為了能夠達(dá)到這個(gè)暫停目標(biāo)。
5.1 特點(diǎn)
- 全年代垃圾回收器
- G1負(fù)責(zé)全年代的垃圾回收,不像前面幾種垃圾回收器,如:Serial(新生代)需要配合SerialOld(老年代)、CMS(老年代)需要配合ParNew(新生代)
- G1對(duì)堆的劃分方式不一樣
- 在G1之前,堆空間被“切”成兩份,分別是:新生代、老年代,
- 而G1并沒(méi)有按照傳統(tǒng)方式去劃分,G1將整個(gè)堆空間劃分為一個(gè)一個(gè)相同大小的Region,而每個(gè)Region要么屬于新生代,要么屬于老年代,而每個(gè)新生代或老年代的Region在物理上不是一塊連續(xù)的物理地址。而每個(gè)Region也不一定在整個(gè)項(xiàng)目周期中完全屬于新生代或老年代而是處于一種動(dòng)態(tài)變化的過(guò)程中。
- 每次回收某個(gè)代并不會(huì)全部進(jìn)行掃描回收
- 回收價(jià)值:這是每個(gè)Region中帶有的屬性,Calc(對(duì)象的存活率、回收預(yù)計(jì)耗時(shí)、回收效果…)
- 而當(dāng)進(jìn)行回收時(shí),會(huì)優(yōu)先選取回收價(jià)值高的Region,從而減少垃圾回收的區(qū)域。
- 大對(duì)象存儲(chǔ)
- 在以往分代模型中,當(dāng)某個(gè)大對(duì)象進(jìn)入內(nèi)存時(shí),如果整個(gè)新生代在垃圾清理之后依然無(wú)法使用,但是老年代卻有足夠的空間,此時(shí)該大對(duì)象會(huì)直接進(jìn)入到老年代;
- 而在G1中并沒(méi)有使用上述的方式存儲(chǔ)過(guò)大的對(duì)象,而是大對(duì)象會(huì)被安排到了一個(gè)叫Humongous的Region中,在發(fā)生新生代或者老年代垃圾回收時(shí),都會(huì)順帶清理Humongous的Region。
5.2 G1新生代垃圾回收
經(jīng)過(guò)上面的文字分析,新生代的Region個(gè)數(shù)為所有Region個(gè)數(shù)的5%;這個(gè)數(shù)值其實(shí)是很小的,那么當(dāng)新生代Region不夠用的時(shí)候,JVM會(huì)劃分更多的Region個(gè)數(shù)給新生代;
當(dāng)新生代的Region個(gè)數(shù)占比所有Region個(gè)數(shù)超過(guò) 60%時(shí),就會(huì)進(jìn)行一次新生代的垃圾回收。
新生代垃圾回收會(huì)造成STW。
具體的垃圾回收算法同其它幾個(gè)新生代垃圾回收器一樣,新生代都使用復(fù)制算法。
5.3 G1老年代垃圾回收
老年代垃圾回收觸發(fā)機(jī)制與參數(shù)-XX:InitaingHeapOccupancyPercent有關(guān)。
但是需要注意的是:這一次的老年代回收,其實(shí)是一次混合垃圾回收,會(huì)同時(shí)清理新生代、老年代、Humongous。
與新生代回收算法一致,依然使用復(fù)制算法,但是垃圾回收的過(guò)程等同于老年代響應(yīng)時(shí)間優(yōu)先的CMS方式
流程分為: