醒酒菜:動(dòng)畫圖解核心內(nèi)存區(qū)--堆

端午佳節(jié)一下子就過(guò)完了软啼,大家是不是還沉迷在假期的歡樂(lè)氣氛中無(wú)法自拔饱普?今天阿Q為大家準(zhǔn)備了上好的“醒酒菜”——JVM運(yùn)行時(shí)數(shù)據(jù)區(qū)的核心內(nèi)存區(qū)——堆溯饵。

堆的概述

一般來(lái)說(shuō):

  • 一個(gè)Java程序的運(yùn)行對(duì)應(yīng)一個(gè)進(jìn)程七冲;
  • 一個(gè)進(jìn)程對(duì)應(yīng)著一個(gè)JVM實(shí)例(JVM的啟動(dòng)由引導(dǎo)類加載器加載啟動(dòng)),同時(shí)也對(duì)應(yīng)著多個(gè)線程殿较;
  • 一個(gè)JVM實(shí)例擁有一個(gè)運(yùn)行時(shí)數(shù)據(jù)區(qū)(Runtime類耸峭,為餓漢式單例類);
  • 一個(gè)運(yùn)行時(shí)數(shù)據(jù)區(qū)中的堆和方法區(qū)是多線程共享的淋纲,而本地方法棧劳闹、虛擬機(jī)棧、程序計(jì)數(shù)器是線程私有的洽瞬。

堆空間差不多是最大的內(nèi)存空間本涕,也是運(yùn)行時(shí)數(shù)據(jù)區(qū)最重要的內(nèi)存空間。堆可以處于物理上不連續(xù)的內(nèi)存空間片任,但在邏輯上它應(yīng)該被視為連續(xù)的偏友。

在方法結(jié)束后,堆中的對(duì)象不會(huì)馬上被移除对供,僅僅在垃圾收集的時(shí)候才會(huì)被移除位他。堆,是GC(Garbage Collection产场,垃圾收集器)執(zhí)行垃圾回收的重點(diǎn)區(qū)域鹅髓。

堆內(nèi)存大小設(shè)置

堆一旦被創(chuàng)建,它的大小也就確定了京景,初始內(nèi)存默認(rèn)為電腦物理內(nèi)存大小的1/64窿冯,最大內(nèi)存默認(rèn)為電腦物理內(nèi)存的1/4,但是堆空間的大小是可以調(diào)節(jié)确徙,接下來(lái)我們來(lái)演示一下醒串。

準(zhǔn)備工具

JDK自帶內(nèi)存分析的工具:在已安裝JDKbin目錄下找到jvisualvm.exe。打開(kāi)該軟件鄙皇,下載插件Visual GC芜赌,一定要點(diǎn)擊檢查最新版本,否則會(huì)導(dǎo)致安裝失敗伴逸。

image

安裝完重啟jvisualvm

image

代碼樣例

public class HeapDemo {
    public static void main(String[] args) {
        System.out.println("start...");
        try {
            Thread.sleep(1000000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("end...");
    }
}

IDEA設(shè)置

image
image
  • -Xms10m用于表示堆區(qū)的起始內(nèi)存為10m缠沈,等價(jià)于-XX:InitialHeapSize
  • -Xmx10m用于表示堆區(qū)的最大內(nèi)存為10m错蝴,等價(jià)于-XX:MaxHeapSize洲愤;
  • 其中-XJVM的運(yùn)行參數(shù),msmemory start

?

通常會(huì)將-Xms-Xmx兩個(gè)參數(shù)配置相同的值顷锰,其目的就是為了能夠在java垃圾回收機(jī)制清理完堆區(qū)后不需要重新分隔計(jì)算堆區(qū)的大小柬赐,從而提高性能。

?

啟動(dòng)程序

啟動(dòng)程序之后去jvisualvm查看

image

一旦堆區(qū)中的內(nèi)存大小超過(guò)-Xmx所指定的最大內(nèi)存時(shí)官紫,將會(huì)拋出OOM(Out Of MemoryError)異常躺率。

堆的分代

存儲(chǔ)在JVM中的java對(duì)象可以被劃分為兩類:

  • 一類是生命周期較短的瞬時(shí)對(duì)象玛界,這類對(duì)象的創(chuàng)建和消亡都非常迅速;
  • 另一類是生命周期非常長(zhǎng)悼吱,在某些情況下還能與JVM的生命周期保持一致堂飞;

堆區(qū)分代

經(jīng)研究表明70%-99%的對(duì)象屬于臨時(shí)對(duì)象圃泡,為了提高GC的性能张足,Hotspot虛擬機(jī)又將堆區(qū)進(jìn)行了進(jìn)一步劃分蛙讥。

image

如圖所示,堆區(qū)又分為年輕代(YoungGen)和老年代(OldGen)遇西;其中年輕代又分為伊甸園區(qū)(Eden)和幸存者區(qū)(Survivor);幸存者區(qū)分為幸存者0區(qū)(Survivor0粱檀,S0)和幸存者1區(qū)(Survivor1洲敢,S1),有時(shí)也叫from區(qū)和to區(qū)茄蚯。

?

分代完成之后压彭,GC時(shí)主要檢測(cè)新生代Eden區(qū)。

?

「統(tǒng)一概念:」
新生區(qū)<=>新生代<=>年輕代
養(yǎng)老區(qū)<=>老年區(qū)<=>老年代

幾乎所有的Java對(duì)象都是在Eden區(qū)被new出來(lái)的渗常,有的大對(duì)象在該區(qū)存不下可直接進(jìn)入老年代壮不。絕大部分的Java對(duì)象都銷毀在新生代了(IBM公司的專門研究表明,新生代80%的對(duì)象都是“朝生夕死”的)皱碘。

新生代與老年代在堆結(jié)構(gòu)的占比

  • 默認(rèn)參數(shù)-XX:NewRatio=2询一,表示新生代占1,老年代占2癌椿,新生代占整個(gè)堆的1/3健蕊;
  • 可以修改-XX:NewRatio=4,表示新生代占1踢俄,老年代占4绊诲,新生代占整個(gè)堆的1/5;

?

該參數(shù)在開(kāi)發(fā)中一般不會(huì)調(diào)整,如果生命周期長(zhǎng)的對(duì)象偏多時(shí)可以選擇調(diào)整褪贵。

?

Eden與Survivor在堆結(jié)構(gòu)的占比

HotSpot中,Eden空間和另外兩個(gè)Survivor空間所占的比例是8:1:1(測(cè)試的時(shí)候是6:1:1)抗俄,開(kāi)發(fā)人員可以通過(guò)選項(xiàng)-XX:SurvivorRatio調(diào)整空間比例脆丁,如-XX:SurvivorRatio=8

?

可以在cmd中通過(guò)jps 查詢進(jìn)程號(hào)-> jinfo -flag NewRatio(SurvivorRatio) + 進(jìn)程號(hào) 查詢配置信息

?

-Xmn設(shè)置新生代最大內(nèi)存大小(默認(rèn)就好)动雹,如果既設(shè)置了該參數(shù)槽卫,又設(shè)置了NewRatio的值,則以該參數(shù)設(shè)置為準(zhǔn)胰蝠。

查看設(shè)置的參數(shù)

以上邊的代碼為例:設(shè)置啟動(dòng)參數(shù)-XX:+PrintGCDetails歼培;可在cmd窗口中輸入jps查詢進(jìn)程號(hào)震蒋,然后通過(guò)jstat -gc 進(jìn)程id指令查看進(jìn)程的內(nèi)存使用情況。

image

圖解對(duì)象分配過(guò)程

對(duì)象分配過(guò)程

image
  1. new的對(duì)象先放伊甸園區(qū)躲庄,此區(qū)有大小限制查剖;
  2. 當(dāng)伊甸園的空間填滿時(shí),程序繼續(xù)創(chuàng)建對(duì)象噪窘,JVM的垃圾回收器將對(duì)伊甸園區(qū)進(jìn)行垃圾回收(Minor GC笋庄,也叫YGC):將伊甸園區(qū)中的不再被其他對(duì)象所引用的對(duì)象進(jìn)行銷毀,將未被銷毀的對(duì)象移動(dòng)到幸存者0區(qū)并分配age倔监;
  3. 然后再加載新的對(duì)象放到伊甸園區(qū)直砂;
  4. 如果再次觸發(fā)垃圾回收,將此次未被銷毀的對(duì)象和上一次放在幸存者0區(qū)且此次也未被銷毀的對(duì)象一齊移動(dòng)到幸存者一區(qū)浩习,此時(shí)新對(duì)象的age為1静暂,上次的對(duì)象的age加1變?yōu)?;
  5. 如果再次經(jīng)歷垃圾回收谱秽,此時(shí)會(huì)重新放回幸存者0區(qū)洽蛀,接著再去幸存者1區(qū),age也隨之增加弯院;
  6. 默認(rèn)當(dāng)age為15時(shí)辱士,未被回收的對(duì)象將移動(dòng)到老年區(qū)√可以通過(guò)設(shè)置參數(shù)來(lái)更改默認(rèn)配置:-XX:MaxTenuringThreshold=<N>颂碘;該過(guò)程稱為晉升(promotion);
  7. 在養(yǎng)老區(qū)椅挣,相對(duì)悠閑头岔,當(dāng)老年區(qū)內(nèi)存不足時(shí),再次觸發(fā)GC(Major GC)鼠证,進(jìn)行養(yǎng)老區(qū)的內(nèi)存清理峡竣;
  8. 若養(yǎng)老區(qū)執(zhí)行了Major GC之后發(fā)現(xiàn)依然無(wú)法進(jìn)行對(duì)象的保存,就會(huì)產(chǎn)生OOM異常量九。

?

S0适掰,S1滿時(shí)不會(huì)觸發(fā)YGC,但是YGC會(huì)回收S0荠列,S1的對(duì)象类浪。

?

「總結(jié)」

  • 針對(duì)幸存者s0,s1區(qū):復(fù)制之后有交換肌似,誰(shuí)空誰(shuí)是to费就;
  • 關(guān)于垃圾回收:頻繁在新生區(qū)收集,很少在養(yǎng)老區(qū)收集川队,幾乎不再永久區(qū)/元空間收集力细。

對(duì)象特殊情況分配過(guò)程

image
  1. 新對(duì)象申請(qǐng)內(nèi)存睬澡,如果Eden放的下,則直接存入Eden眠蚂;如果存不下則進(jìn)行YGC煞聪;
  2. YGC之后如果能存下則放入Eden,如果還存不下(為超大對(duì)象)河狐,則嘗試存入Old區(qū)米绕;
  3. 如果Old區(qū)可以存放,則存入馋艺;如果不能存入栅干,則進(jìn)行Full GC
  4. Full GC之后如果可以存入Old區(qū)捐祠,則存入碱鳞;如果內(nèi)存空間還不夠,則OOM踱蛀;
  5. 圖右側(cè)為YGC的流程圖:當(dāng)YGC之后未銷毀的對(duì)象放入幸存者區(qū)窿给,此時(shí)如果幸存者區(qū)的空間可以裝下該對(duì)象,則存入幸存者區(qū)率拒,否則崩泡,直接存入老年代;
  6. 當(dāng)在幸存者區(qū)的對(duì)象超過(guò)閾值時(shí)猬膨,可以晉升為老年代角撞,未達(dá)到閾值的依舊在幸存者區(qū)復(fù)制交換。

內(nèi)存分配策略

針對(duì)不同年齡段的對(duì)象分配原則如下:

  1. 優(yōu)先分配到Eden勃痴;
  2. 大對(duì)象直接分配到老年代:盡量避免程序中出現(xiàn)過(guò)多的大對(duì)象谒所;
  3. 長(zhǎng)期存活的對(duì)象分配到老年代;
  4. 動(dòng)態(tài)對(duì)象年齡判斷:如果Survivor區(qū)中相同年齡的所有對(duì)象大小的總和大于Survivor空間的一半沛申,年齡大于或等于該年齡的對(duì)象可以直接進(jìn)入到老年代劣领。無(wú)需等到MaxTenuringThreshold中要求的年齡;

數(shù)值變小原理

代碼樣例铁材,設(shè)置參數(shù):-Xms600m尖淘,-Xmx600m

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

        //返回Java虛擬機(jī)中的堆內(nèi)存總量
        long initialMemory = Runtime.getRuntime().totalMemory() / 1024 / 1024;
        //返回Java虛擬機(jī)試圖使用的最大堆內(nèi)存量
        long maxMemory = Runtime.getRuntime().maxMemory() / 1024 / 1024;

        System.out.println("-Xms : " + initialMemory + "M");
        System.out.println("-Xmx : " + maxMemory + "M");

        try {
            Thread.sleep(1000000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
//執(zhí)行結(jié)果
-Xms : 575M
-Xmx : 575M

明明設(shè)置的600M,怎么變成575M了呢著觉?這是因?yàn)樵诙褍?nèi)存存取數(shù)據(jù)時(shí)村生,新生代里邊只有伊甸園和幸存者1區(qū)或者是幸存者2區(qū)存儲(chǔ)對(duì)象,所以會(huì)少一個(gè)幸存者區(qū)的內(nèi)存空間固惯。

GC

JVM進(jìn)行GC時(shí),并非每次都對(duì)新生代缴守、老年代葬毫、方法區(qū)(永久代镇辉、元空間)這三個(gè)區(qū)域一起回收,大部分回收是指新生代贴捡。

針對(duì)HotSpot VM的實(shí)現(xiàn)忽肛,它里面的GC按照回收區(qū)域又分為兩大種類型:一種是部分收集(Partial GC),一種是整堆收集(Full GC

Partial GC

部分收集:不是完整收集整個(gè)Java堆的垃圾收集烂斋。其中又分為:

  • 新生代收集(Minor GC/Young GC):只是新生代的垃圾收集屹逛;
  • 老年代收集(Major GC/Old GC):只是老年代的垃圾收集;
  • 混合收集(Mixed GC):收集整個(gè)新生代以及部分老年代的垃圾收集汛骂,只有G1 GC (按照region劃分新生代和老年代的數(shù)據(jù))會(huì)有這種行為罕模。

目前,只有CMS GC會(huì)有單獨(dú)收集老年代的行為帘瞭;很多時(shí)候Major GC會(huì)和Full GC 混淆使用淑掌,需要具體分辨是老年代回收還是整堆回收。

Full GC

整堆收集(Full GC):整個(gè)java堆和方法區(qū)的垃圾收集蝶念。

觸發(fā)機(jī)制

年輕代GC(Minor GC)觸發(fā)機(jī)制
  1. 當(dāng)年輕代空間不足時(shí)抛腕,就會(huì)觸發(fā)Minor GC,這里的年輕代滿指的是Eden代滿媒殉,Survivor滿不會(huì)引發(fā)GC担敌。(每次Minor GC會(huì)清理年輕代的內(nèi)存,Survivor是被動(dòng)GC廷蓉,不會(huì)主動(dòng)GC)
  2. 因?yàn)?code>Java對(duì)象大多都具備“朝生夕滅”的特性全封,所以Minor GC非常頻繁,一般回收速度也比較快苦酱。
  3. Minor GC會(huì)引發(fā)STWStop The World)售貌,暫停其他用戶的線程,等垃圾回收結(jié)束疫萤,用戶線程才恢復(fù)運(yùn)行颂跨。
老年代GC(Major GC/Full GC)觸發(fā)機(jī)制
  1. 指發(fā)生在老年代的GC,對(duì)象從老年代消失時(shí)扯饶,Major GC或者Full GC發(fā)生了恒削;
  2. 出現(xiàn)了Major GC,經(jīng)常會(huì)伴隨至少一次的Minor GC(不是絕對(duì)的尾序,在Parallel Scavenge收集器的收集策略里就有直接進(jìn)行Major GC的策略選擇過(guò)程)钓丰,也就是老年代空間不足時(shí),會(huì)先嘗試觸發(fā)Minor GC每币。如果之后空間還不足携丁,則觸發(fā)Major GC
  3. Major GC速度一般會(huì)比Minor GC慢10倍以上,STW時(shí)間更長(zhǎng)梦鉴;
  4. 如果Major GC后李茫,內(nèi)存還不足,就報(bào)OOM了肥橙。
Full GC觸發(fā)機(jī)制

觸發(fā)Full GC執(zhí)行的情況有以下五種:

  1. 調(diào)用System.gc()時(shí)魄宏,系統(tǒng)建議執(zhí)行Full GC,但是不必然執(zhí)行存筏;
  2. 老年代空間不足宠互;
  3. 方法區(qū)空間不足;
  4. 通過(guò)Minor GC后進(jìn)入老年代的平均大小小于老年代的可用內(nèi)存椭坚;
  5. Eden區(qū)予跌,Survivor S0from)區(qū)向S1to)區(qū)復(fù)制時(shí),對(duì)象大小大于To Space可用內(nèi)存藕溅,則把該對(duì)象轉(zhuǎn)存到老年代匕得,且老年代的可用內(nèi)存小于該對(duì)象大小。

?

Full GC是開(kāi)發(fā)或調(diào)優(yōu)中盡量要避免的巾表,這樣暫停時(shí)間會(huì)短一些汁掠。

?

以上就是今天的所有內(nèi)容了,如果你有不同的意見(jiàn)或者更好的idea集币,歡迎聯(lián)系阿Q:qingqing-4132考阱,阿Q期待你的到來(lái)!

后臺(tái)留言領(lǐng)取java干貨資料:學(xué)習(xí)筆記與大廠面試題

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末鞠苟,一起剝皮案震驚了整個(gè)濱河市乞榨,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌当娱,老刑警劉巖吃既,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異跨细,居然都是意外死亡鹦倚,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門冀惭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)震叙,“玉大人,你說(shuō)我怎么就攤上這事散休∶铰ィ” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵戚丸,是天一觀的道長(zhǎng)划址。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么夺颤? 我笑而不...
    開(kāi)封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任对人,我火速辦了婚禮,結(jié)果婚禮上拂共,老公的妹妹穿的比我還像新娘。我一直安慰自己姻几,他們只是感情好宜狐,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著蛇捌,像睡著了一般抚恒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上络拌,一...
    開(kāi)封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天俭驮,我揣著相機(jī)與錄音,去河邊找鬼春贸。 笑死混萝,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的萍恕。 我是一名探鬼主播逸嘀,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼允粤!你這毒婦竟也來(lái)了崭倘?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤类垫,失蹤者是張志新(化名)和其女友劉穎司光,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體悉患,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡残家,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了购撼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片跪削。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖迂求,靈堂內(nèi)的尸體忽然破棺而出碾盐,到底是詐尸還是另有隱情,我是刑警寧澤揩局,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布毫玖,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏付枫。R本人自食惡果不足惜烹玉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望阐滩。 院中可真熱鬧二打,春花似錦、人聲如沸掂榔。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)装获。三九已至瑞信,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間穴豫,已是汗流浹背凡简。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留精肃,地道東北人秤涩。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像司抱,于是被迫代替她去往敵國(guó)和親溉仑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容