第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

首頁(yè) 慕課教程 JVM 入門(mén)教程 JVM 入門(mén)教程 JVM 堆的對(duì)象轉(zhuǎn)移與年齡判斷

JVM 中堆的對(duì)象轉(zhuǎn)移與年齡判斷

1. 前言

上節(jié)課程我們講解了堆內(nèi)存中不同內(nèi)存空間模塊的作用、特點(diǎn)及意義,本節(jié)主要講解堆內(nèi)存中對(duì)象的轉(zhuǎn)移與年齡判斷。本節(jié)主要知識(shí)點(diǎn)如下:

  • 理解并掌握對(duì)象優(yōu)先在 Eden 區(qū)分配的實(shí)驗(yàn)案例,為本節(jié)重點(diǎn)內(nèi)容之一;
  • 理解并掌握對(duì)象直接在老年代分配的觸發(fā)條件,理解什么是大對(duì)象,為本節(jié)重點(diǎn)內(nèi)容之一;
  • 掌握堆內(nèi)存對(duì)象轉(zhuǎn)移的完整流程圖及觸發(fā)機(jī)制,為本節(jié)核心知識(shí)點(diǎn),其它所有知識(shí)點(diǎn)都是圍繞這一知識(shí)點(diǎn)展開(kāi)的;
  • 理解并掌握年齡判斷的定義,作用及默認(rèn)年齡值,為本節(jié)重點(diǎn)內(nèi)容之一。

通篇皆為重點(diǎn)內(nèi)容,其核心是圍繞堆內(nèi)存對(duì)象轉(zhuǎn)移的完整流程圖及觸發(fā)機(jī)制,本節(jié)課程的內(nèi)容會(huì)涉及到垃圾回收的相關(guān)概念,此處我們先做了解即可,后續(xù)會(huì)對(duì)垃圾回收進(jìn)行專門(mén)的講解。

2. 對(duì)象優(yōu)先在Eden 區(qū)分配

Tips:標(biāo)題中“優(yōu)先”一次需要學(xué)習(xí)者認(rèn)真品味,“優(yōu)先” 意味著首先考慮,那么在一些特殊情況下,新創(chuàng)建的對(duì)象還是有可能不在Eden區(qū)分配的。這種特殊情況我們?cè)谥v解老年代(OldGen)的時(shí)候再進(jìn)行說(shuō)明。

上節(jié)課程我們學(xué)習(xí)了,Eden 區(qū)屬于年輕代(YoungGen)。在創(chuàng)建新的對(duì)象時(shí),大多數(shù)情況下,對(duì)象先在 Eden 區(qū)中分配。當(dāng) Eden 區(qū)沒(méi)有足夠空間進(jìn)行分配時(shí),虛擬機(jī)將發(fā)起一次 Minor GC。

那我們?nèi)绾芜M(jìn)行證明,新創(chuàng)建的對(duì)象優(yōu)先在Eden 區(qū)分配呢?為了對(duì)這個(gè)結(jié)論進(jìn)行驗(yàn)證,我們來(lái)設(shè)計(jì)如下實(shí)驗(yàn)。

實(shí)驗(yàn)設(shè)計(jì)

  • 創(chuàng)建了一個(gè)類,類名稱可自定義,并在類中實(shí)現(xiàn)一個(gè) main 函數(shù),為后續(xù)測(cè)試做前提準(zhǔn)備;
  • 在運(yùn)行main函數(shù)之前,通過(guò)設(shè)置 JVM 參數(shù),設(shè)置堆內(nèi)存初始大小為 20M,最大為 20M,其中年輕代大小為 10M,不需要特殊設(shè)置 Eden 區(qū)的大?。?/li>
  • 除了設(shè)置堆內(nèi)存參數(shù)之外,還需要設(shè)置JVM 參數(shù)跟蹤詳細(xì)的垃圾回收日志,以便于觀察年輕代(YoungGen)的內(nèi)存使用情況;
  • 設(shè)置完成后,main 函數(shù)不寫(xiě)任何代碼,運(yùn)行空的 main 函數(shù)觀察打印日志;
  • 在main函數(shù)中創(chuàng)建一個(gè) 2M 大小的對(duì)象,運(yùn)行 main 函數(shù)觀察打印日志。

Tips:實(shí)驗(yàn)中會(huì)用到兩種JVM的參數(shù)配置,一種是配置堆內(nèi)存的參數(shù),另外一種是配置跟蹤垃圾回收的參數(shù)。這兩部分參數(shù)我們?cè)谥暗恼鹿?jié)都有詳細(xì)描述過(guò)。

實(shí)驗(yàn)要點(diǎn)準(zhǔn)備

  • 設(shè)置堆內(nèi)存大小為 20M,最大為 20M,其中年輕代大小為 10M,并設(shè)置垃圾跟蹤日志打印。需要通過(guò)JVM參數(shù) -Xms20m -Xmx20m -Xmn10m -XX:+PrintGCDetails 進(jìn)行設(shè)置;
  • 不需要特殊設(shè)置 Eden 區(qū)的大小,那么年輕代中 Eden 區(qū)、from space 和 to space 將會(huì)以默認(rèn)的 8:1:1進(jìn)行空間分配;
  • 創(chuàng)建一個(gè) 2M 大小的對(duì)象,我們可以通過(guò)語(yǔ)句 byte[] obj = new byte[2*1024*1024] 來(lái)實(shí)現(xiàn)。

空運(yùn)行main函數(shù)代碼演示

public class DemoTest {
    public static void main(String[] args) {
    }
}

空運(yùn)行mian函數(shù)日志

Heap
 PSYoungGen      total 9216K, used 2370K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 28% used [0x00000000ff600000,0x00000000ff850aa0,0x00000000ffe00000)
  from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
  to   space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
 ParOldGen       total 10240K, used 0K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 0% used [0x00000000fec00000,0x00000000fec00000,0x00000000ff600000)
 Metaspace       used 3439K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 374K, capacity 388K, committed 512K, reserved 1048576K

結(jié)果分析:我們主要關(guān)注 PSYoungGen(年輕代)下的內(nèi)存分配。空運(yùn)行情況下,我們看到 Eden 區(qū)的大小為 8192K,已使用 28%。為什么空運(yùn)行下還會(huì)有 28% 的內(nèi)存使用呢?這 28% 的內(nèi)存使用,包括了支持main函數(shù)運(yùn)行的對(duì)象實(shí)例。

新建 2M 對(duì)象的代碼演示

public class DemoTest {
    public static void main(String[] args) {
        byte[] obj = new byte[2*1024*1024];
    }
}

新建 2M 對(duì)象的運(yùn)行日志:此處我們只展示年輕代的運(yùn)行日志。

PSYoungGen      total 9216K, used 4418K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 53% used [0x00000000ff600000,0x00000000ffa50ac8,0x00000000ffe00000)

結(jié)果分析:我們看到,新建 2M 的對(duì)象之后,Eden 區(qū)使用的空間從之前的 28% 增長(zhǎng)到了 53%,凈增長(zhǎng) 25%。那么我們來(lái)進(jìn)行簡(jiǎn)單的計(jì)算 Eden 區(qū)的總內(nèi)存大小 8192K * 25% = 2048K = 2M。

看到這里我們應(yīng)該明白了,新創(chuàng)建的對(duì)象確實(shí)是優(yōu)先存儲(chǔ)于年輕代(YoungGen)中的Eden區(qū)的。

3. 大對(duì)象直接進(jìn)入老年代

我們?cè)谶M(jìn)行上一知識(shí)點(diǎn)講解時(shí)提到過(guò),新創(chuàng)建的對(duì)象是優(yōu)先存放入 Eden 區(qū)的,那么對(duì)于新創(chuàng)建的大對(duì)象來(lái)說(shuō),會(huì)直接進(jìn)入老年代碼。

什么是大對(duì)象:2M 的對(duì)象算大嗎?10M 的對(duì)象算大嗎?100M 的對(duì)象呢?什么是大對(duì)象,大對(duì)象的標(biāo)準(zhǔn)是什么?大對(duì)象的標(biāo)準(zhǔn)是可以由開(kāi)發(fā)者定義的,我們的 JVM 參數(shù)中,能夠通過(guò) -XX:PretenureSizeThreshold 這個(gè)參數(shù)設(shè)置大對(duì)象的標(biāo)準(zhǔn),可惜的是這個(gè)參數(shù)只對(duì) Serial 和 ParNew 兩款新生代收集器有效。

那么如果不能夠設(shè)置 -XX:PretenureSizeThreshold 參數(shù),那什么是大對(duì)象呢?Eden 區(qū)容量不夠存放的對(duì)象就是所謂的大對(duì)象。

為了驗(yàn)證“大對(duì)象直接進(jìn)入老年代”這一結(jié)論,我們依然通過(guò)實(shí)驗(yàn)進(jìn)行驗(yàn)證。

實(shí)驗(yàn)設(shè)計(jì)

  • 沿用上一個(gè)實(shí)驗(yàn)的 JVM 參數(shù)設(shè)置,并在此基礎(chǔ)上增加參數(shù)設(shè)置 -XX:PretenureSizeThreshold = 3m;
  • 將新建的 2M 對(duì)象修改為新建 6M對(duì)象;
  • 運(yùn)行 main 函數(shù),觀察日志結(jié)果。

實(shí)驗(yàn)要點(diǎn)準(zhǔn)備:本實(shí)驗(yàn)所需的 JVM 參數(shù)為 -Xms20m -Xmx20m -Xmn10m -XX:+PrintGCDetails。

代碼示例

public class DemoTest {
    public static void main(String[] args) {
        byte[] obj = new byte[6*1024*1024];
    }
}

運(yùn)行結(jié)果

Heap
 PSYoungGen      total 9216K, used 2370K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 28% used [0x00000000ff600000,0x00000000ff850aa0,0x00000000ffe00000)
  from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
  to   space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
 ParOldGen       total 10240K, used 6020K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 58% used [0x00000000fec00000,0x00000000ff1e1010,0x00000000ff600000)
 Metaspace       used 3439K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 374K, capacity 388K, committed 512K, reserved 1048576K

結(jié)果分析:我們先來(lái)看下老年代(OldGen),total 10240K, used 6020K,說(shuō)明我們新創(chuàng)建的對(duì)象是直接進(jìn)入了老年代。然后我們來(lái)看下 Eden區(qū) 為什么不能存儲(chǔ) 6M 大小的對(duì)象,我們進(jìn)行簡(jiǎn)單的計(jì)算。

Eden 區(qū)剩余內(nèi)存空間 = 總空間 8192K * (1-28%)= 5898 K < 6M。這就是我們所說(shuō)的,大對(duì)象直接進(jìn)入老年代。

4. 對(duì)象轉(zhuǎn)移流程

上文我們學(xué)習(xí)了 Eden 區(qū)優(yōu)先存放新建的獨(dú)享,新建大對(duì)象不會(huì)經(jīng)過(guò)Eden區(qū),直接進(jìn)入老年代,那么還剩兩個(gè)區(qū)域沒(méi)有進(jìn)行講解:幸存者區(qū) from space 和 幸存者區(qū) to space。我們?cè)趯?duì)流程圖進(jìn)行講解時(shí),會(huì)對(duì)這兩塊內(nèi)存區(qū)域進(jìn)行說(shuō)明。

圖片描述

從上圖中可以看出,新生成的非大對(duì)象首先放到年輕代 Eden 區(qū),當(dāng) Eden 空間滿了,觸發(fā) Minor GC,存活下來(lái)的對(duì)象移動(dòng)到 Survivor0 區(qū),Survivor0 區(qū)滿后觸發(fā)執(zhí)行 Minor GC,Survivor0 區(qū)存活對(duì)象移動(dòng)到 Suvivor1 區(qū),這樣保證了一段時(shí)間內(nèi)總有一個(gè) survivor 區(qū)為空。經(jīng)過(guò)多次 Minor GC 仍然存活的對(duì)象移動(dòng)到老年代。

如果新生成的是大對(duì)象,會(huì)直接將該對(duì)象存放入老年代。

老年代存儲(chǔ)長(zhǎng)期存活的對(duì)象,GC 期間會(huì)停止所有線程等待 GC 完成,所以對(duì)響應(yīng)要求高的應(yīng)用盡量減少發(fā)生 Major GC,避免響應(yīng)超時(shí)。

5. 對(duì)象年齡判斷

對(duì)象年齡判斷的作用:JVM 通過(guò)判斷對(duì)象的具體年齡來(lái)判別是否該對(duì)象應(yīng)存入老年代,JVM通過(guò)對(duì)年齡的判斷來(lái)完成從對(duì)象從年輕代到老年代的轉(zhuǎn)移。

對(duì)象年齡(Age)計(jì)數(shù)器:HotSpot 虛擬機(jī)中多數(shù)收集器都采用了分代收集來(lái)管理堆內(nèi)存,那內(nèi)存回收時(shí)就必須能決策哪些存活對(duì)象應(yīng)當(dāng)放在新生代,哪些存活對(duì)象放在老年代中。為做到這點(diǎn),虛擬機(jī)給每個(gè)對(duì)象定義了一個(gè)對(duì)象年齡(Age)計(jì)數(shù)器,存儲(chǔ)在對(duì)象頭中。

年齡增加:對(duì)象通常在 Eden 區(qū)里誕生,如果經(jīng)過(guò)第一次 Minor GC 后仍然存活,并且能被Survivor容納的話,該對(duì)象會(huì)被移動(dòng)到 Survivor 空間中,并且將其對(duì)象年齡設(shè)為 1 歲。對(duì)象在Survivor區(qū)中每熬過(guò)一次 Minor GC,年齡就增加 1 歲。

年齡默認(rèn)閾值:當(dāng)它的年齡增加到一定程度(默認(rèn)為15),就會(huì)被晉升到老年代中。對(duì)象晉升老年代的年齡閾值,可以通過(guò)參數(shù) -XX:MaxTenuringThreshold 設(shè)置。

6. 小結(jié)

本節(jié)我們學(xué)習(xí)了堆內(nèi)存對(duì)象的轉(zhuǎn)移過(guò)程以及 JVM 是如何通過(guò)判斷對(duì)象年齡來(lái)決定是否將對(duì)象從年輕代轉(zhuǎn)移至老年代的。通篇皆為重點(diǎn)內(nèi)容,學(xué)習(xí)者需認(rèn)真對(duì)待,本節(jié)內(nèi)容與垃圾回收也息息相關(guān),學(xué)好本節(jié)課程,也能為后續(xù)垃圾回收部分打下良好的基礎(chǔ)。