當(dāng)前位置:首頁(yè) > 公眾號(hào)精選 > 架構(gòu)師社區(qū)
[導(dǎo)讀]今天來(lái)說(shuō)說(shuō) Java 垃圾回收,高頻面試問(wèn)題。

大家好,我是狂聊,上一篇已經(jīng)把 Jvm 的運(yùn)行區(qū)數(shù)據(jù)和類(lèi)加載機(jī)制聊完了。

今天來(lái)說(shuō)說(shuō) Java 垃圾回收,高頻面試問(wèn)題。

提綱附上,話不多說(shuō),直接干貨

假期三天,我肝了萬(wàn)字的Java垃圾回收,看完你還敢說(shuō)不會(huì)?

1、什么是垃圾回收?

垃圾回收(Garbage Collection,GC):就是釋放垃圾占用的空間,防止內(nèi)存泄露。對(duì)內(nèi)存堆中已經(jīng)死亡的或者長(zhǎng)時(shí)間沒(méi)有使用的對(duì)象進(jìn)行清除和回收。

2、垃圾在哪兒?

假期三天,我肝了萬(wàn)字的Java垃圾回收,看完你還敢說(shuō)不會(huì)?

上圖可以看到程序計(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á)的。

假期三天,我肝了萬(wàn)字的Java垃圾回收,看完你還敢說(shuō)不會(huì)?

從上圖可以看到,即使 Object5 和 Object6 之間相互引用,但是沒(méi)有 GC Roots 和它們關(guān)聯(lián),所以可以解決循環(huán)引用的問(wèn)題。

小知識(shí)點(diǎn):

1、哪些可以作為 GC ROOTS 根呢?

  1. 虛擬機(jī)棧(棧幀中的本地變量表)中引用的對(duì)象
  2. 方法區(qū)中類(lèi)靜態(tài)屬性引用的對(duì)象
  3. 方法區(qū)中常量引用的對(duì)象
  4. 本地方法棧中 JNI(即一般說(shuō)的 Native 方法)引用的對(duì)象

2、不得不說(shuō)的四種引用

  1. 強(qiáng)引用:就是在程序中普遍存在的,類(lèi)似“Object a=new Object”這類(lèi)的引用。 只要強(qiáng)引用關(guān)系還存在,垃圾回收器就不會(huì)回收掉被引用的對(duì)象。
  2. 軟引用:用來(lái)描述一些還有用但是并非必須的對(duì)象。 直到內(nèi)存空間不夠時(shí)(拋出 OutOfMemoryError 之前),才會(huì)被垃圾回收,通過(guò) SoftReference 來(lái)實(shí)現(xiàn)。
  3. 弱引用:比軟引用還弱,也是用來(lái)描述非必須的對(duì)象的, 當(dāng)垃圾回收器開(kāi)始工作時(shí),無(wú)論內(nèi)存是否足夠用,弱引用的關(guān)聯(lián)的對(duì)象都會(huì)被回收 WeakReference。
  4. 虛引用:它是最弱的一種引用關(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ò)程和一次篩選。

一張圖帶你看明白:

假期三天,我肝了萬(wàn)字的Java垃圾回收,看完你還敢說(shuō)不會(huì)?

5、垃圾收集算法

1、標(biāo)記清除算法

分為兩個(gè)階段“標(biāo)記”和“清除”,標(biāo)記出所有要回收的對(duì)象,然后統(tǒng)一進(jìn)行清除。

假期三天,我肝了萬(wàn)字的Java垃圾回收,看完你還敢說(shuō)不會(huì)?

缺點(diǎn):

  1. 在對(duì)象變多的情況下,標(biāo)記和清除效率都不高
  2. 會(huì)產(chǎn)生空間碎片

2、復(fù)制算法

就是將堆分成兩塊完全相同的區(qū)域,對(duì)象只在其中一塊區(qū)域內(nèi)分配,然后標(biāo)記出那些是存活的對(duì)象,按順序整體移到另外一個(gè)空間,然后回收掉之前那個(gè)區(qū)域的所有對(duì)象。

假期三天,我肝了萬(wàn)字的Java垃圾回收,看完你還敢說(shuō)不會(huì)?

缺點(diǎn):

  1. 雖然能夠解決空間碎片的問(wèn)題,但是空間少了一半。也太多了吧?。?

3、標(biāo)記整理算法

假期三天,我肝了萬(wàn)字的Java垃圾回收,看完你還敢說(shuō)不會(huì)?

這種算法是,先找到存活的對(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ō)明可以搭配使用。

假期三天,我肝了萬(wàn)字的Java垃圾回收,看完你還敢說(shuō)不會(huì)?

Serial

Serial 收集器是一個(gè)單線程收集器,在進(jìn)行垃圾回收器的時(shí)候,必須暫停其他工作線程,也就是發(fā)生 STW。在 GC 期間,應(yīng)用是不可用的。

假期三天,我肝了萬(wàn)字的Java垃圾回收,看完你還敢說(shuō)不會(huì)?

特點(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)速度。

假期三天,我肝了萬(wàn)字的Java垃圾回收,看完你還敢說(shuō)不會(huì)?

特點(diǎn):1、采用復(fù)制算法  2、多線程收集器  3、效率高,能大大減少 STW 時(shí)間。

Parallel Scavenge

Parallel Scavenge 收集器也是一個(gè)使用復(fù)制算法,多線程,工作于新生代的垃圾收集器,看起來(lái)功能和 ParNew 收集器基本一樣。

假期三天,我肝了萬(wàn)字的Java垃圾回收,看完你還敢說(shuō)不會(huì)?

但是它有啥特別之處呢?關(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 收集器配合使用示意圖如下:

假期三天,我肝了萬(wàn)字的Java垃圾回收,看完你還敢說(shuō)不會(huì)?

特點(diǎn):1、標(biāo)記-整理算法 2、單線程 3、老年代工作

Parallel Old

Parallel Old 是一個(gè)多線程的垃圾回收器,采用標(biāo)記整理算法,負(fù)責(zé)老年代的垃圾回收工作,可以與 Parallel Scavenge 垃圾回收器一起搭配工作。真正的實(shí)現(xiàn)吞吐量?jī)?yōu)先

示意圖如下:

假期三天,我肝了萬(wàn)字的Java垃圾回收,看完你還敢說(shuō)不會(huì)?

特點(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)記清除算法

示意圖如下:

假期三天,我肝了萬(wàn)字的Java垃圾回收,看完你還敢說(shuō)不會(huì)?

垃圾回收的 4 個(gè)步驟:

  1. 初始標(biāo)記:標(biāo)記出來(lái)和 GC Roots 直接關(guān)聯(lián)的對(duì)象,整個(gè)速度是非常快的,會(huì)發(fā)生 STW,確保標(biāo)記的準(zhǔn)確性。
  2. 并發(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ì)有很大的影響。
  3. 重新標(biāo)記:這個(gè)階段是為了解決第二步并發(fā)標(biāo)記所導(dǎo)致的標(biāo)錯(cuò)情況。并發(fā)階段會(huì)和用戶線程并行,有可能會(huì)出現(xiàn)判斷錯(cuò)誤的情況,這個(gè)階段就是對(duì)上一個(gè)階段的修正。
  4. 并發(fā)清除:最后一個(gè)階段,將之前確認(rèn)為垃圾的對(duì)象進(jìn)行回收,會(huì)和用戶線程一起并發(fā)執(zhí)行。

缺點(diǎn):

  1. 影響用戶線程的執(zhí)行效率:CMS 默認(rèn)啟動(dòng)的回收線程數(shù)是(處理器核心數(shù) + 3)/ 4 ,由于是和用戶線程一起并發(fā)清理,那么勢(shì)必會(huì)影響到用戶線程的執(zhí)行速度
  2. 會(huì)產(chǎn)生浮動(dòng)垃圾:CMS 的第 4 個(gè)階段 并發(fā)清除是和用戶線程一起的,會(huì)產(chǎn)生新的垃圾,就叫浮動(dòng)垃圾
  3. 會(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)行回收。

先看下堆空間的劃分:

假期三天,我肝了萬(wàn)字的Java垃圾回收,看完你還敢說(shuō)不會(huì)?

G1 垃圾回收器把堆劃分成大小相同的 Region,每個(gè) Region 都會(huì)扮演一個(gè)角色,分別為 H、S、E、O。

  1. E 代表伊甸區(qū)
  2. S 代表 Survivor 區(qū)
  3. H 代表的是 Humongous 區(qū)
  4. O 代表 Old 區(qū)

G1 的工作流程圖:

假期三天,我肝了萬(wàn)字的Java垃圾回收,看完你還敢說(shuō)不會(huì)?
  • 初始標(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):

  1. 并行與并發(fā):G1 能充分利用多 CPU、多核環(huán)境下的硬件優(yōu)勢(shì),可以通過(guò)并發(fā)的方式讓 Java 程序繼續(xù)執(zhí)行,進(jìn)一步縮短 STW 的時(shí)間。
  2. 分代收集:分代概念在 G1 中依然得以保留,它能夠采用不同的方式去處理新創(chuàng)建的對(duì)象和已經(jīng)存活了一段時(shí)間、熬過(guò)多次 GC 的舊對(duì)象來(lái)獲得更好的收集效果。
  3. 空間整合:G1 從整體上看是基于標(biāo)記-整理算法實(shí)現(xiàn)的,從局部(兩個(gè) Region 之間)上看是基于復(fù)制算法實(shí)現(xiàn)的,G1 運(yùn)行期間不會(huì)產(chǎn)生內(nèi)存空間碎片。
  4. 可預(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):

假期三天,我肝了萬(wàn)字的Java垃圾回收,看完你還敢說(shuō)不會(huì)?

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)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車(chē)的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車(chē)技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車(chē)工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車(chē)。 SODA V工具的開(kāi)發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車(chē) 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來(lái)越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開(kāi)幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉