假期三天,我肝了萬(wàn)字的Java垃圾回收,看完你還敢說(shuō)不會(huì)?
大家好,我是狂聊,上一篇已經(jīng)把 Jvm 的運(yùn)行區(qū)數(shù)據(jù)和類(lèi)加載機(jī)制聊完了。
今天來(lái)說(shuō)說(shuō) Java 垃圾回收,高頻面試問(wèn)題。
提綱附上,話不多說(shuō),直接干貨
1、什么是垃圾回收?
垃圾回收(Garbage Collection,GC):就是釋放垃圾占用的空間,防止內(nèi)存泄露。對(duì)內(nèi)存堆中已經(jīng)死亡的或者長(zhǎng)時(shí)間沒(méi)有使用的對(duì)象進(jìn)行清除和回收。
2、垃圾在哪兒?
上圖可以看到程序計(jì)數(shù)器、虛擬機(jī)棧、本地方法棧都是伴隨著線程而生死,這些區(qū)域不需要進(jìn)行 GC。
而方法區(qū)/元空間在 1.8 之后就直接放到本地內(nèi)存了,假設(shè)總內(nèi)存 2G,JVM 被分配內(nèi)存 100M, 理論上元空間可以分配 2G-100M = 1.9G,空間還是足夠的,所以這塊區(qū)域也不用管。
所以就只剩下堆了,java 對(duì)象實(shí)例和數(shù)組都是在堆上分配的,所以垃圾回收器重點(diǎn)照顧堆。
3、怎么發(fā)現(xiàn)它?
在發(fā)生 GC 的時(shí)候,Jvm 是怎么判斷堆中的對(duì)象實(shí)例是不是垃圾呢?
這里有兩種方式:
1、引用計(jì)數(shù)法
就是給對(duì)象中添加一個(gè)引用計(jì)數(shù)器,每當(dāng)有一個(gè)地方引用它時(shí),計(jì)數(shù)器的值就加 1,每當(dāng)有一個(gè)引用失效時(shí),計(jì)數(shù)器的值就減 1。任何時(shí)刻只要對(duì)象的計(jì)數(shù)器值為 0,那么就可以被判定為垃圾對(duì)象。
這種方式,效率挺高,但是 Jvm 并沒(méi)有使用引用計(jì)數(shù)算法。那是因?yàn)樵谀撤N場(chǎng)合下存在問(wèn)題
比如下面的代碼,會(huì)出現(xiàn)循環(huán)引用的問(wèn)題:
public class Test { Test test; public Test(String name) {} public static void main(String[] args) { Test a = new Test("A"); Test b = new Test("B"); a.test = b; b.test = a; a = null; b = null; } }
即使你把 a 和 b 的引用都置為 null 了,計(jì)數(shù)器也不是 0,而是 1,因?yàn)樗鼈冎赶虻膶?duì)象又互相指向了對(duì)方,所以無(wú)法回收這兩個(gè)對(duì)象。
2、可達(dá)性分析法
這才是 jvm 默認(rèn)使用的尋找垃圾算法。
它的原理是通過(guò)一些列稱為“GC Roots”的對(duì)象作為起始點(diǎn),從這些節(jié)點(diǎn)開(kāi)始向下搜索,搜素所走過(guò)的路叫做稱為引用鏈“Reference Chain”,當(dāng)一個(gè)對(duì)象到 GC Roots 沒(méi)有任何引用鏈時(shí),就說(shuō)這個(gè)對(duì)象是不可達(dá)的。
從上圖可以看到,即使 Object5 和 Object6 之間相互引用,但是沒(méi)有 GC Roots 和它們關(guān)聯(lián),所以可以解決循環(huán)引用的問(wèn)題。
小知識(shí)點(diǎn):
1、哪些可以作為 GC ROOTS 根呢?
-
虛擬機(jī)棧(棧幀中的本地變量表)中引用的對(duì)象
-
方法區(qū)中類(lèi)靜態(tài)屬性引用的對(duì)象
-
方法區(qū)中常量引用的對(duì)象
-
本地方法棧中 JNI(即一般說(shuō)的 Native 方法)引用的對(duì)象
2、不得不說(shuō)的四種引用
-
強(qiáng)引用:就是在程序中普遍存在的,類(lèi)似“Object a=new Object”這類(lèi)的引用。 只要強(qiáng)引用關(guān)系還存在,垃圾回收器就不會(huì)回收掉被引用的對(duì)象。
-
軟引用:用來(lái)描述一些還有用但是并非必須的對(duì)象。 直到內(nèi)存空間不夠時(shí)(拋出 OutOfMemoryError 之前),才會(huì)被垃圾回收,通過(guò) SoftReference 來(lái)實(shí)現(xiàn)。
-
弱引用:比軟引用還弱,也是用來(lái)描述非必須的對(duì)象的, 當(dāng)垃圾回收器開(kāi)始工作時(shí),無(wú)論內(nèi)存是否足夠用,弱引用的關(guān)聯(lián)的對(duì)象都會(huì)被回收 WeakReference。
-
虛引用:它是最弱的一種引用關(guān)系,它的唯一作用是用來(lái)作為一種通知。 采用 PhantomRenference 實(shí)現(xiàn)。
3、為什么定義這些引用?
個(gè)人理解,其實(shí)就是給對(duì)象加一種中間態(tài),讓一個(gè)對(duì)象不只有引用和非引用兩種情況,還可以描述一些“食之無(wú)味棄之可惜”的對(duì)象。比如說(shuō):當(dāng)內(nèi)存空間足時(shí),則能保存在內(nèi)存中,如果內(nèi)存空間在進(jìn)行垃圾回收之后還不夠時(shí),才對(duì)這些對(duì)象進(jìn)行回收。
4、生存還是死亡?
要真正宣告一個(gè)對(duì)象死亡,至少要經(jīng)歷兩次標(biāo)記過(guò)程和一次篩選。
一張圖帶你看明白:
5、垃圾收集算法
1、標(biāo)記清除算法
分為兩個(gè)階段“標(biāo)記”和“清除”,標(biāo)記出所有要回收的對(duì)象,然后統(tǒng)一進(jìn)行清除。
缺點(diǎn):
-
在對(duì)象變多的情況下,標(biāo)記和清除效率都不高
-
會(huì)產(chǎn)生空間碎片
2、復(fù)制算法
就是將堆分成兩塊完全相同的區(qū)域,對(duì)象只在其中一塊區(qū)域內(nèi)分配,然后標(biāo)記出那些是存活的對(duì)象,按順序整體移到另外一個(gè)空間,然后回收掉之前那個(gè)區(qū)域的所有對(duì)象。
缺點(diǎn):
-
雖然能夠解決空間碎片的問(wèn)題,但是空間少了一半。也太多了吧?。?
3、標(biāo)記整理算法
這種算法是,先找到存活的對(duì)象,然后將它們向空間的一端移動(dòng),最后回收掉邊界以外的垃圾對(duì)象。
4、分代收集
其實(shí)就是整合了上面三種算法,揚(yáng)長(zhǎng)避短。
之所以叫分代,是因?yàn)楦鶕?jù)對(duì)象存活周期的不同將整個(gè) Java 堆切割成為三個(gè)部分:
-
Young(年輕代)
-
Eden(伊利園):新生對(duì)象
-
Survivor(幸存者):垃圾回收后還活著的對(duì)象
-
Tenured(老年代):對(duì)象多次回收都沒(méi)有被清理,會(huì)移到老年代
-
Perm(永久代):存放加載的類(lèi)別還有方法對(duì)象,java8 之后移除了永久代,替換為元空間(Metaspace)
在新生代中,每次垃圾收集都有大量的對(duì)象死去,只有少量的存活,那就選用 復(fù)制算法 ,因?yàn)閺?fù)制成本很小,只需要復(fù)制少量存活對(duì)象。
老年代中,存活對(duì)象較多,沒(méi)有額外的空間擔(dān)保,就得使用 標(biāo)記清除 或者 標(biāo)記整理 。
6、垃圾收集器
在說(shuō)垃圾回收器之前需要了解幾個(gè)概念:
1、幾個(gè)概念
吞吐量
CPU 用于運(yùn)行用戶代碼的時(shí)間與 CPU 總消耗時(shí)間的比值。
比如說(shuō)虛擬機(jī)總運(yùn)行了 100 分鐘,用戶代碼時(shí)間 99 分鐘,垃圾回收時(shí)間 1 分鐘,那么吞吐量就是 99%。
STW
全稱 Stop-The-World,即在 GC 期間,只有垃圾回收器線程在工作,其他工作線程則被掛起。
為什么需要 STW 呢?
在 java 程序中引用關(guān)系是不斷會(huì)變化的,那么就會(huì)有很多種情況來(lái)導(dǎo)致垃圾標(biāo)識(shí)出錯(cuò)。
想想一下如果一個(gè)對(duì)象 A 當(dāng)前是個(gè)垃圾,GC 把它標(biāo)記為垃圾,但是在清除前又有其他引用指向了 A,那么此刻又不是垃圾了。
那么,如果沒(méi)有 STW 的話,就要去無(wú)限維護(hù)這種關(guān)系來(lái)去采集正確的信息,顯然是不可取的。
安全點(diǎn)
從線程角度看,安全點(diǎn)可以理解成是在代碼執(zhí)行過(guò)程中的一些特殊位置,當(dāng)線程執(zhí)行到這些位置的時(shí)候,說(shuō)明虛擬機(jī)當(dāng)前的狀態(tài)是安全的。
比如:方法調(diào)用、循環(huán)跳轉(zhuǎn)、異常跳轉(zhuǎn)等這些地方才會(huì)產(chǎn)生安全點(diǎn)。
如果有需要,可以在這個(gè)位置暫停,比如發(fā)生 GC 時(shí),需要暫停所有活動(dòng)線程,但是線程在這個(gè)時(shí)刻,還沒(méi)有執(zhí)行到一個(gè)安全點(diǎn),所以該線程應(yīng)該繼續(xù)執(zhí)行,到達(dá)下一個(gè)安全點(diǎn)的時(shí)候暫停,等待 GC 結(jié)束。
串行、并行
串行:是指垃圾回收線程在進(jìn)行垃圾回收工作,此時(shí)用戶線程處于等待狀態(tài)。
并行:是指用戶線程和多條垃圾回收線程分別在不同 CPU 上同時(shí)工作。
2、回收器
下面是一張很經(jīng)典的圖,展示了 7 種不同分代的收集器,如果兩個(gè)收集器之間存在連線,說(shuō)明可以搭配使用。
Serial
Serial 收集器是一個(gè)單線程收集器,在進(jìn)行垃圾回收器的時(shí)候,必須暫停其他工作線程,也就是發(fā)生 STW。在 GC 期間,應(yīng)用是不可用的。
特點(diǎn):1、采用復(fù)制算法 2、單線程收集器 3、效率會(huì)比較慢,但是因?yàn)槭菃尉€程,所以消耗內(nèi)存小
ParNew
ParNew 是 Serial 的多線程版本,也是工作在新生代,能與 CMS 配合使用。
在多 CPU 的情況下,由于 ParNew 的多線程回收特性,毫無(wú)疑問(wèn)垃圾收集會(huì)更快,也能有效地減少 STW 的時(shí)間,提升應(yīng)用的響應(yīng)速度。
特點(diǎn):1、采用復(fù)制算法 2、多線程收集器 3、效率高,能大大減少 STW 時(shí)間。
Parallel Scavenge
Parallel Scavenge 收集器也是一個(gè)使用復(fù)制算法,多線程,工作于新生代的垃圾收集器,看起來(lái)功能和 ParNew 收集器基本一樣。
但是它有啥特別之處呢?關(guān)注點(diǎn)不同
-
ParNew 垃圾收集器關(guān)注的是盡可能縮短垃圾收集時(shí)用戶線程的停頓時(shí)間,更適合用到與用戶交互的程序,因?yàn)橥nD時(shí)間越短,用戶體驗(yàn)肯定就好呀??!
-
Parallel Scavenge 目標(biāo)是達(dá)到一個(gè)可控制的吞吐量,所以更適合做后臺(tái)運(yùn)算等不需要太多用戶交互的任務(wù)。
Parallel Scavenge 收集器提供了兩個(gè)參數(shù)來(lái)控制吞吐量,
-
-XX:MaxGCPauseMillis:控制最大垃圾收集時(shí)間
-
-XX:GCTimeRati:直接設(shè)置吞吐量大小
特點(diǎn):1、采用復(fù)制算法 2、多線程收集器 3、吞吐量?jī)?yōu)先
Serial Old
Serial 收集器是工作于新生代的單線程收集器,與之相對(duì)地,Serial Old 是工作于老年代的單線程收集器。
作用:
-
在 Client 模式下與 Serial 回收器配合使用
-
Server 模式下,則它還有兩大用途:一種是在 JDK 1.5 及之前的版本中與 Parallel Scavenge 配合使用,另一種是作為 CMS 收集器的后備預(yù)案,在并發(fā)收集發(fā)生 Concurrent Mode Failure 時(shí)使用
它與 Serial 收集器配合使用示意圖如下:
特點(diǎn):1、標(biāo)記-整理算法 2、單線程 3、老年代工作
Parallel Old
Parallel Old 是一個(gè)多線程的垃圾回收器,采用標(biāo)記整理算法,負(fù)責(zé)老年代的垃圾回收工作,可以與 Parallel Scavenge 垃圾回收器一起搭配工作。真正的實(shí)現(xiàn)吞吐量?jī)?yōu)先
示意圖如下:
特點(diǎn):1、標(biāo)記-整理算法 2、多線程 3、老年代工作
CMS
CMS 可以說(shuō)是一款具有"跨時(shí)代"意義的垃圾回收器,如果應(yīng)用很重視服務(wù)的響應(yīng)速度,希望給用戶最好的體驗(yàn),則 CMS 收集器是非常合適的,它是以獲取最短回收停頓時(shí)間為目標(biāo)的收集器!
CMS 雖然工作在老年代,和之前收集器不同的是,使用的標(biāo)記清除算法
示意圖如下:
垃圾回收的 4 個(gè)步驟:
-
初始標(biāo)記:標(biāo)記出來(lái)和 GC Roots 直接關(guān)聯(lián)的對(duì)象,整個(gè)速度是非常快的,會(huì)發(fā)生 STW,確保標(biāo)記的準(zhǔn)確性。
-
并發(fā)標(biāo)記:并發(fā)標(biāo)記這個(gè)階段會(huì)直接根據(jù)第一步關(guān)聯(lián)的對(duì)象找到所有的引用關(guān)系,耗時(shí)較長(zhǎng),但是這個(gè)階段會(huì)與用戶線程并發(fā)運(yùn)行,不會(huì)有很大的影響。
-
重新標(biāo)記:這個(gè)階段是為了解決第二步并發(fā)標(biāo)記所導(dǎo)致的標(biāo)錯(cuò)情況。并發(fā)階段會(huì)和用戶線程并行,有可能會(huì)出現(xiàn)判斷錯(cuò)誤的情況,這個(gè)階段就是對(duì)上一個(gè)階段的修正。
-
并發(fā)清除:最后一個(gè)階段,將之前確認(rèn)為垃圾的對(duì)象進(jìn)行回收,會(huì)和用戶線程一起并發(fā)執(zhí)行。
缺點(diǎn):
-
影響用戶線程的執(zhí)行效率:CMS 默認(rèn)啟動(dòng)的回收線程數(shù)是(處理器核心數(shù) + 3)/ 4 ,由于是和用戶線程一起并發(fā)清理,那么勢(shì)必會(huì)影響到用戶線程的執(zhí)行速度
-
會(huì)產(chǎn)生浮動(dòng)垃圾:CMS 的第 4 個(gè)階段 并發(fā)清除是和用戶線程一起的,會(huì)產(chǎn)生新的垃圾,就叫浮動(dòng)垃圾
-
會(huì)產(chǎn)生碎片化的空間:標(biāo)記清除的缺點(diǎn)
G1
全稱:Garbage-First
G1 回收的目標(biāo)不再是整個(gè)新生代或者是老年代。G1 可以回收堆內(nèi)存的任何空間來(lái)進(jìn)行,不再是根據(jù)年代來(lái)區(qū)分,而是那塊空間垃圾多就去回收,通過(guò) Mixed GC 的方式去進(jìn)行回收。
先看下堆空間的劃分:
G1 垃圾回收器把堆劃分成大小相同的 Region,每個(gè) Region 都會(huì)扮演一個(gè)角色,分別為 H、S、E、O。
-
E 代表伊甸區(qū)
-
S 代表 Survivor 區(qū)
-
H 代表的是 Humongous 區(qū)
-
O 代表 Old 區(qū)
G1 的工作流程圖:
-
初始標(biāo)記:標(biāo)記出來(lái) GC Roots 能直接關(guān)聯(lián)到的對(duì)象,修改 TAMS 的值以便于并發(fā)回收時(shí)新對(duì)象分配
-
并發(fā)標(biāo)記:根據(jù)剛剛關(guān)聯(lián)的對(duì)像掃描整個(gè)對(duì)象引用圖,和用戶線程并發(fā)執(zhí)行,記錄 SATB(原始快照) 在并發(fā)時(shí)有引用的值
-
最終標(biāo)記:處理第二步遺留下來(lái)的少量 SATB(原始快照) 記錄,會(huì)發(fā)生 STW
-
篩選回收:維護(hù)之前提到的優(yōu)先級(jí)列表,根據(jù)優(yōu)先級(jí)列表、用戶設(shè)置的最大暫停時(shí)間來(lái)回收 Region
特點(diǎn):
-
并行與并發(fā):G1 能充分利用多 CPU、多核環(huán)境下的硬件優(yōu)勢(shì),可以通過(guò)并發(fā)的方式讓 Java 程序繼續(xù)執(zhí)行,進(jìn)一步縮短 STW 的時(shí)間。
-
分代收集:分代概念在 G1 中依然得以保留,它能夠采用不同的方式去處理新創(chuàng)建的對(duì)象和已經(jīng)存活了一段時(shí)間、熬過(guò)多次 GC 的舊對(duì)象來(lái)獲得更好的收集效果。
-
空間整合:G1 從整體上看是基于標(biāo)記-整理算法實(shí)現(xiàn)的,從局部(兩個(gè) Region 之間)上看是基于復(fù)制算法實(shí)現(xiàn)的,G1 運(yùn)行期間不會(huì)產(chǎn)生內(nèi)存空間碎片。
-
可預(yù)測(cè)停頓:G1 比 CMS 厲害在能建立可預(yù)測(cè)的停頓時(shí)間模型,能讓使用者明確指定在一個(gè)長(zhǎng)度為 M 毫秒的時(shí)間片段內(nèi),消耗在垃圾收集上的時(shí)間不得超過(guò) N 毫秒。
7、內(nèi)存分配與回收策略
上文說(shuō)的一直都是回收內(nèi)存的內(nèi)容,那么怎么給對(duì)象分配內(nèi)存呢?
堆空間的結(jié)構(gòu):
Eden 區(qū)
研究表明,有將近 98%的對(duì)象是朝生夕死,所以針對(duì)這一現(xiàn)狀,大多數(shù)情況下,對(duì)象會(huì)在新生代 Eden 區(qū)中進(jìn)行分配。
當(dāng) Eden 區(qū)沒(méi)有足夠空間進(jìn)行分配時(shí),虛擬機(jī)會(huì)發(fā)起一次 Minor GC,Minor GC 相比 Major GC 更頻繁,回收速度也更快。
通過(guò) Minor GC 之后,Eden 會(huì)被清空,Eden 區(qū)中絕大部分對(duì)象會(huì)被回收,而那些無(wú)需回收的存活對(duì)象,將會(huì)進(jìn)到 Survivor 的 From 區(qū)(若 From 區(qū)不夠,則直接進(jìn)入 Old 區(qū))。
Survivor 區(qū)
Survivor 區(qū)相當(dāng)于是 Eden 區(qū)和 Old 區(qū)的一個(gè)緩沖,Survivor 又分為 2 個(gè)區(qū),一個(gè)是 From 區(qū),一個(gè)是 To 區(qū)。每次執(zhí)行 Minor GC,會(huì)將 Eden 區(qū)和 From 存活的對(duì)象放到 Survivor 的 To 區(qū)(如果 To 區(qū)不夠,則直接進(jìn)入 Old 區(qū))。
問(wèn)題 1:為什么需要 Survivor?
如果沒(méi)有 Survivor 區(qū),Eden 區(qū)每進(jìn)行一次 Minor GC,存活的對(duì)象就會(huì)被送到老年代,老年代很快就會(huì)被填滿。而有很多對(duì)象雖然一次 Minor GC 沒(méi)有消滅,但其實(shí)或許第二次,第三次就需要被清除。
這時(shí)候移入老年區(qū),很明顯不是一個(gè)明智的決定。
所以,Survivor 的存在意義就是減少被送到老年代的對(duì)象,進(jìn)而減少老年代 GC 的發(fā)生。Survivor 的預(yù)篩選保證,只有經(jīng)歷 15 次 Minor GC 還能在新生代中存活的對(duì)象,才會(huì)被送到老年代。
問(wèn)題 2:為什么需要 From 和 To 兩個(gè)呢?
這種機(jī)制最大的好處就是可以解決內(nèi)存碎片化,整個(gè)過(guò)程中,永遠(yuǎn)有一個(gè) Survivor 區(qū)是空的,另一個(gè)非空的 Survivor 區(qū)是無(wú)碎片的。
假設(shè)只有一個(gè) Survivor 區(qū)。
Minor GC 執(zhí)行后,Eden 區(qū)被清空了,存活的對(duì)象放到了 Survivor 區(qū),而之前 Survivor 區(qū)中的對(duì)象,可能也有一些是需要被清除的。
那么問(wèn)題來(lái)了,這時(shí)候我們?cè)趺辞宄鼈儯?
在這種場(chǎng)景下,我們只能標(biāo)記清除,而我們知道標(biāo)記清除最大的問(wèn)題就是內(nèi)存碎片,在新生代這種經(jīng)常會(huì)消亡的區(qū)域,采用標(biāo)記清除必然會(huì)讓內(nèi)存產(chǎn)生嚴(yán)重的碎片化。
因?yàn)?Survivor 有 2 個(gè)區(qū)域,所以每次 Minor GC,會(huì)將之前 Eden 區(qū)和 From 區(qū)中的存活對(duì)象復(fù)制到 To 區(qū)域。第二次 Minor GC 時(shí),To 區(qū) 到 From 區(qū) ,以此反復(fù)。
Old 區(qū)
老年代占據(jù)著 2/3 的堆內(nèi)存空間,只有在 Major GC 的時(shí)候才會(huì)進(jìn)行清理,每次 GC 都會(huì)觸發(fā)“Stop-The-World”。內(nèi)存越大,STW 的時(shí)間也越長(zhǎng),所以內(nèi)存也不僅僅是越大就越好。
由于復(fù)制算法在對(duì)象存活率較高的老年代會(huì)進(jìn)行很多次的復(fù)制操作,效率很低,所以在這里老年代采用的是標(biāo)記整理算法。
下面三種情況也會(huì)直接進(jìn)入老年代:
大對(duì)象
大對(duì)象指需要大量連續(xù)內(nèi)存空間的對(duì)象,這部分對(duì)象不管是不是“朝生夕死”,都會(huì)直接進(jìn)到老年代。這樣做主要是為了避免在 Eden 區(qū)及 2 個(gè) Survivor 區(qū)之間發(fā)生大量的內(nèi)存復(fù)制。當(dāng)你的系統(tǒng)有非常多“朝生夕死”的大對(duì)象時(shí),需要注意。
長(zhǎng)期存活對(duì)象
虛擬機(jī)給每個(gè)對(duì)象定義了一個(gè)對(duì)象年齡 Age 計(jì)數(shù)器。正常情況下對(duì)象會(huì)不斷的在 Survivor 的 From 區(qū)與 To 區(qū)之間移動(dòng),對(duì)象在 Survivor 區(qū)中每經(jīng)歷一次 Minor GC,年齡就增加 1 歲。當(dāng)年齡增加到 15 歲時(shí),這時(shí)候就會(huì)被轉(zhuǎn)移到老年代。
動(dòng)態(tài)對(duì)象年齡
虛擬機(jī)并不重視要求對(duì)象年齡必須到 15 歲,才會(huì)放入老年區(qū),如果 Survivor 空間中相同年齡所有對(duì)象大小的總合大于 Survivor 空間的一半,年齡大于等于該年齡的對(duì)象就可以直接進(jìn)去老年區(qū)。
空間分配擔(dān)保
在發(fā)生 Minor GC 之前,虛擬機(jī)會(huì)先檢查老年代最大可用的連續(xù)空間是否大于新生代所有對(duì)象總空間。
如果條件成立的話,Minor GC 是可以確保安全的。
如果不成立,則虛擬機(jī)會(huì)查看 HandlePromotionFailure 設(shè)置是否擔(dān)保失敗,如果允許,那么會(huì)繼續(xù)檢查老年代最大可用的連續(xù)空間是否大于歷次晉升到老年代對(duì)象的平均大小。
如果大于,嘗試進(jìn)行一次 Minor GC。
如果小于或者 HandlePromotionFailure 不允許,則進(jìn)行一次 Full GC。
免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問(wèn)題,請(qǐng)聯(lián)系我們,謝謝!