JVM內(nèi)存分配擔(dān)保機(jī)制

在現(xiàn)實(shí)社會(huì)中绰播,借款會(huì)指定擔(dān)保人滔韵,就是當(dāng)借款人還不起錢宴卖,就由擔(dān)保人來還錢肝谭。

在JVM的內(nèi)存分配時(shí)医寿,也有這樣的內(nèi)存分配擔(dān)保機(jī)制沟突。就是當(dāng)在新生代無法分配內(nèi)存的時(shí)候,把新生代的對(duì)象轉(zhuǎn)移到老生代,然后把新對(duì)象放入騰空的新生代秀鞭。

現(xiàn)在假設(shè)剩辟,我們的新生代分為三個(gè)區(qū)域,分別為eden space,from space和to space刺桃。

現(xiàn)在是嘗試分配三個(gè)2MB的對(duì)象和一個(gè)4MB的對(duì)象,然后我們通過JVM參數(shù) -Xms20M、-Xmx20M逼纸、-Xmn10M 把Java堆大小設(shè)置為20MB,不可擴(kuò)展哥力。

其中10M分配給新生代吩跋,另外10M分配給老生代。

然后我們通過-XX:SurvivorRatio=8來分配新生代各區(qū)的比例旺韭,設(shè)置為8,表示eden與一個(gè)survivor區(qū)的空間比例為8:1悔政。

image.png

圖1 新生代內(nèi)存分配

JVM參數(shù)配置:

-Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+UseSerialGC

這里我們先手動(dòng)指定垃圾收集器為客戶端模式下的Serial+Serial Old的收集器組合進(jìn)行內(nèi)存回收近弟。

由于不同的收集器的收集機(jī)制不同鳖敷,為了呈現(xiàn)出內(nèi)存分配的擔(dān)保效果定踱,我們這里需要手動(dòng)指定為Serial+Serial Old模式。

另外擔(dān)保機(jī)制在JDK1.5以及之前版本中默認(rèn)是關(guān)閉的哺壶,需要通過HandlePromotionFailure手動(dòng)指定屋吨,JDK1.6之后就默認(rèn)開啟。這里我們使用的是JDK1.8山宾,所以不用再手動(dòng)去開啟擔(dān)保機(jī)制至扰。

下面我們新建四個(gè)byte數(shù)組,前三個(gè)分別為2MB大小的內(nèi)存分配资锰,第四個(gè)是4MB的內(nèi)存分配敢课。代碼如下:

image.png

然后運(yùn)行程序,看看GC日志:

[GC (Allocation Failure) [DefNew: 7836K->472K(9216K), 0.0120087 secs] 7836K->6616K(19456K), 0.0123203 secs] [Times: user=0.01 sys=0.01, real=0.01 secs]

Heap

def new generation total 9216K, used 4732K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)

eden space 8192K, 52% used [0x00000007bec00000, 0x00000007bf0290f0, 0x00000007bf400000)

from space 1024K, 46% used [0x00000007bf500000, 0x00000007bf576018, 0x00000007bf600000)

to space 1024K, 0% used [0x00000007bf400000, 0x00000007bf400000, 0x00000007bf500000)

tenured generation total 10240K, used 6144K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)

the space 10240K, 60% used [0x00000007bf600000, 0x00000007bfc00030, 0x00000007bfc00200, 0x00000007c0000000)

Metaspace used 3160K, capacity 4494K, committed 4864K, reserved 1056768K

class space used 341K, capacity 386K, committed 512K, reserved 1048576K

通過GC日志我們發(fā)現(xiàn)在分配allocation4的時(shí)候绷杜,發(fā)生了一次Minor GC直秆,讓新生代從7836K變?yōu)榱?72K,但是你發(fā)現(xiàn)整個(gè)堆的占用并沒有多少變化鞭盟。這是因?yàn)榍懊嫒齻€(gè)2MB的對(duì)象都還存活著圾结,所以回收器并沒有找到可回收的對(duì)象。但為什么會(huì)出現(xiàn)這次GC呢齿诉?

image.png

圖2 正常流程把前三個(gè)對(duì)象放入了新生代Eden區(qū)

如果你算一筆賬就知道了筝野,前面三個(gè)對(duì)象2MB+2MB+2MB=6MB

虛擬機(jī)分配內(nèi)存優(yōu)先會(huì)分配到新生代的eden space粤剧,通過圖1我們知道新生代可用內(nèi)存一共只有9216KB歇竟,現(xiàn)在新生代已經(jīng)被用去了6MB,還剩下9216KB-6144KB=3072KB抵恋,然而第四個(gè)對(duì)象是4MB焕议,顯然在新生代已經(jīng)裝不下了。

image.png

圖3 第四個(gè)對(duì)象此時(shí)無法放入Eden區(qū)

于是發(fā)生了一次Minor GC弧关!

而且本次GC期間盅安,虛擬機(jī)發(fā)現(xiàn)eden space的三個(gè)對(duì)象(6MB)又無法全部放入Survivor空間(Survivor可用內(nèi)存只有1MB)唤锉。

這時(shí)候該怎么辦呢?第四個(gè)對(duì)象還要不要分配呢宽堆?

此時(shí)腌紧,JVM就啟動(dòng)了內(nèi)存分配的擔(dān)保機(jī)制,把這6MB的三個(gè)對(duì)象直接轉(zhuǎn)移到了老年代畜隶。

此時(shí)就把新生代的空間騰出來了,然后把第四個(gè)對(duì)象(4MB)放入了Eden區(qū)中号胚,所以你看到的結(jié)果是4096/8192=0.5籽慢,也就是約50%:

eden space 8192K, 52% used [0x00000007bec00000, 0x00000007bf0290f0, 0x00000007bf400000)

老年代則被占用了6MB,也就是前三個(gè)對(duì)象猫胁,102423=6144KB箱亿,6144KB/10240KB=0.6也就是60%:

the space 10240K, 60% used [0x00000007bf600000, 0x00000007bfc00030, 0x00000007bfc00200, 0x00000007c0000000)

image.png

圖4:擔(dān)保后,allocation4放入到新生代eden區(qū)

image.png

圖5:擔(dān)保后弃秆,之前在新生代的三個(gè)對(duì)象轉(zhuǎn)移到了老生代

服務(wù)端模式下的擔(dān)保機(jī)制實(shí)現(xiàn)

上面我們演示的在客戶端模式(Serial+Serial Old)的場(chǎng)景下的結(jié)果届惋,接下來我們使用服務(wù)端模式(Parallel Scavenge+Serial Old的組合)來看看擔(dān)保機(jī)制的實(shí)現(xiàn)。

修改GC組合為:-XX:+UseParallelGC

然后我們運(yùn)行程序看看GC日志菠赚。

  • 第四個(gè)對(duì)象是4MB的情況下:

[GC (Allocation Failure) [PSYoungGen: 6156K->592K(9216K)] 6156K->4696K(19456K), 0.0032059 secs] [Times: user=0.01 sys=0.01, real=0.01 secs]

Heap

PSYoungGen total 9216K, used 7057K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)

eden space 8192K, 78% used [0x00000007bf600000,0x00000007bfc505f8,0x00000007bfe00000)

from space 1024K, 57% used [0x00000007bfe00000,0x00000007bfe94010,0x00000007bff00000)

to space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000)

ParOldGen total 10240K, used 4104K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)

object space 10240K, 40% used [0x00000007bec00000,0x00000007bf002020,0x00000007bf600000)

Metaspace used 3299K, capacity 4494K, committed 4864K, reserved 1056768K

class space used 357K, capacity 386K, committed 512K, reserved 1048576K

  • 第四個(gè)對(duì)象是3MB的情況下:

[GC (Allocation Failure) [PSYoungGen: 8192K->544K(9216K)] 8192K->6688K(19456K), 0.0052943 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]

[Full GC (Ergonomics) [PSYoungGen: 544K->0K(9216K)] [ParOldGen: 6144K->6627K(10240K)] 6688K->6627K(19456K), [Metaspace: 3286K->3286K(1056768K)], 0.0063048 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]

Heap

PSYoungGen total 9216K, used 3238K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)

eden space 8192K, 39% used [0x00000007bf600000,0x00000007bf929918,0x00000007bfe00000)

from space 1024K, 0% used [0x00000007bfe00000,0x00000007bfe00000,0x00000007bff00000)

to space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000)

ParOldGen total 10240K, used 6627K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)

object space 10240K, 64% used [0x00000007bec00000,0x00000007bf278f70,0x00000007bf600000)

Metaspace used 3294K, capacity 4494K, committed 4864K, reserved 1056768K

class space used 356K, capacity 386K, committed 512K, reserved 1048576K

發(fā)現(xiàn)當(dāng)我們使用Server模式下的ParallelGC收集器組合(Parallel Scavenge+Serial Old的組合)下脑豹,擔(dān)保機(jī)制的實(shí)現(xiàn)和之前的Client模式下(SerialGC收集器組合)有所變化。在GC前還會(huì)進(jìn)行一次判斷衡查,如果要分配的內(nèi)存>=Eden區(qū)大小的一半瘩欺,那么會(huì)直接把要分配的內(nèi)存放入老年代中。否則才會(huì)進(jìn)入擔(dān)保機(jī)制拌牲。

這里我們的第四個(gè)對(duì)象是4MB的時(shí)候俱饿,也就是(1024KB*4)/8192KB=0.5,剛好一半塌忽,于是就這第四個(gè)對(duì)象分配到了老年代拍埠。

第二次,我們把第四個(gè)對(duì)象由4MB土居,改為3MB枣购,此時(shí)3MB/8192KB=0.37,顯然不到一半装盯,此時(shí)發(fā)現(xiàn)3MB還是無法放入坷虑,那么就執(zhí)行擔(dān)保機(jī)制,把前三個(gè)對(duì)象轉(zhuǎn)移到老生代埂奈,然后把第四個(gè)對(duì)象(3MB)放入eden區(qū)迄损。

總結(jié)

內(nèi)存分配是在JVM在內(nèi)存分配的時(shí)候,新生代內(nèi)存不足時(shí)账磺,把新生代的存活的對(duì)象搬到老生代芹敌,然后新生代騰出來的空間用于為分配給最新的對(duì)象痊远。這里老生代是擔(dān)保人。在不同的GC機(jī)制下氏捞,也就是不同垃圾回收器組合下碧聪,擔(dān)保機(jī)制也略有不同。在Serial+Serial Old的情況下液茎,發(fā)現(xiàn)放不下就直接啟動(dòng)擔(dān)保機(jī)制逞姿;在Parallel Scavenge+Serial Old的情況下,卻是先要去判斷一下要分配的內(nèi)存是不是>=Eden區(qū)大小的一半捆等,如果是那么直接把該對(duì)象放入老生代滞造,否則才會(huì)啟動(dòng)擔(dān)保機(jī)制。

本文分享自微信公眾號(hào) - ImportSource(importsource)栋烤,作者:賀卓凡

原文出處及轉(zhuǎn)載信息見文內(nèi)詳細(xì)說明谒养,如有侵權(quán),請(qǐng)聯(lián)系 yunjia_community@tencent.com 刪除明郭。

原始發(fā)表時(shí)間:2017-12-10

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末买窟,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子薯定,更是在濱河造成了極大的恐慌始绍,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沉唠,死亡現(xiàn)場(chǎng)離奇詭異疆虚,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)满葛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門径簿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人嘀韧,你說我怎么就攤上這事篇亭。” “怎么了锄贷?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵译蒂,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我谊却,道長(zhǎng)柔昼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任炎辨,我火速辦了婚禮捕透,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己乙嘀,他們只是感情好末购,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著虎谢,像睡著了一般盟榴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上婴噩,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天擎场,我揣著相機(jī)與錄音,去河邊找鬼讳推。 笑死顶籽,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的银觅。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼坏为,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼究驴!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起匀伏,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤洒忧,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后够颠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體熙侍,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年履磨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蛉抓。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡剃诅,死狀恐怖巷送,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情矛辕,我是刑警寧澤笑跛,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站聊品,受9級(jí)特大地震影響飞蹂,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜翻屈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一陈哑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦芥颈、人聲如沸惠勒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)纠屋。三九已至,卻和暖如春盾计,著一層夾襖步出監(jiān)牢的瞬間售担,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工署辉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留族铆,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓哭尝,卻偏偏與公主長(zhǎng)得像哥攘,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子材鹦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

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