JVM淺談一

前言

? ? 由于先前也遇到過一些性能問題,OOM算是其中的一大類了模她。因此也對(duì)jvm產(chǎn)生了一些興趣努潘。自己對(duì)jvm略做了些研究。后續(xù)繼續(xù)補(bǔ)充客给。

從oom引申出去

? ? 既然說到oom用押,首先需要知道oom的原因是什么。為啥會(huì)oom嘞靶剑?

? ? oom的定義是outofmemory,當(dāng)內(nèi)存想為對(duì)象分配內(nèi)存的時(shí)候只恨,發(fā)現(xiàn)內(nèi)存不足以去分配內(nèi)存译仗。或者gc的時(shí)候發(fā)現(xiàn)沒有可以被回收的對(duì)象或回收后的內(nèi)存也不足以為對(duì)象分配內(nèi)存官觅。因此拋出這個(gè)java異常纵菌。

oom

可以分為以下四類

堆溢出:java堆

棧溢出:虛擬機(jī)棧和本地方法棧

方法區(qū)內(nèi)存溢出:方法區(qū)和內(nèi)存時(shí)常量池

本機(jī)直接內(nèi)存溢出

因此,需要先了解堆休涤,棧咱圆,方法區(qū)都是些啥

運(yùn)行時(shí)數(shù)據(jù)區(qū)

先上圖



程序計(jì)數(shù)器:當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器。

? ? java虛擬機(jī)的多線程是通過輪流切換線程功氨,并為線程分配執(zhí)行時(shí)間片去運(yùn)行來執(zhí)行的序苏。每個(gè)線程都有一個(gè)自己的程序計(jì)數(shù)器。我覺得這個(gè)可以這么理解:當(dāng)一個(gè)線程在運(yùn)行的時(shí)候捷凄,每執(zhí)行一步程序計(jì)數(shù)器都會(huì)有個(gè)記錄忱详,記錄當(dāng)前執(zhí)行到哪一步了。如果線程被切換后又切換回來跺涤,那么通過程序計(jì)數(shù)器就能知道執(zhí)行到哪一步了匈睁,然后繼續(xù)向下執(zhí)行。

虛擬機(jī)棧:每個(gè)線程都會(huì)有一個(gè)虛擬機(jī)棧桶错。虛擬機(jī)棧描述的是java方法執(zhí)行的內(nèi)存模型航唆。因?yàn)榫€程執(zhí)行的過程就是執(zhí)行線程里的一個(gè)個(gè)方法,而每個(gè)方法都會(huì)創(chuàng)建對(duì)應(yīng)自己的棧幀院刁。

棧幀里存的內(nèi)容如下:

- 局部變量表:存放了各種編譯期可知基本數(shù)據(jù)類型糯钙,對(duì)象引用(引用指針或句柄)

- 操作數(shù)棧:大多數(shù)指令都要從這里彈出數(shù)據(jù),執(zhí)行運(yùn)算退腥,然后把結(jié)果壓回操作數(shù)棧

- 動(dòng)態(tài)鏈接

- 方法出口

? ? 64位的long和都double類型數(shù)據(jù)占用2個(gè)局部變量空間任岸,其他數(shù)據(jù)類型占用一個(gè),也就是每個(gè)局部變量空間為32位狡刘。

? ? 在這個(gè)地方演闭,如果線程請(qǐng)求的深度大于虛擬機(jī)允許的深度,會(huì)拋出StackOverflowError.因?yàn)閖vm分配給虛擬機(jī)棧的內(nèi)存是有限的颓帝,而每個(gè)方法都會(huì)有對(duì)應(yīng)的棧幀壓入到棧中米碰,如果調(diào)用方法過多,那么棧滿了自然也就溢出了购城。(可能的場景:死循環(huán)代碼吕座,大量遞歸調(diào)用,那排查問題的時(shí)候也可以由此有一個(gè)思路)瘪板∥馀浚可以通過調(diào)整-Xss去調(diào)整棧大小。

大部分java虛擬機(jī)允許動(dòng)態(tài)擴(kuò)展侮攀,但如果擴(kuò)展的時(shí)候也申請(qǐng)不到足夠內(nèi)存時(shí)锣枝,就會(huì)報(bào)OOM了厢拭。

本地方法棧:和虛擬機(jī)發(fā)揮作用相似。區(qū)別:虛擬機(jī)棧為虛擬機(jī)執(zhí)行java方法服務(wù)撇叁,本地方法棧為虛擬機(jī)使用的Native方法服務(wù)供鸠。Native Method就是一個(gè)java調(diào)用非java代碼的接口,Native方法的實(shí)現(xiàn)由非java語言實(shí)現(xiàn)陨闹。讀者不用糾結(jié)楞捂,略作了解即可。

:堆是所有線程共享的一塊內(nèi)存趋厉,作用是存放對(duì)象實(shí)例寨闹。堆可以分為新生代和老年代。新生代里還可細(xì)分為Eden,From survivor,To survivor等空間君账。后面講述GC過程時(shí)會(huì)說到繁堡。

方法區(qū):也是所有線程共享的一塊內(nèi)存,存放被虛擬機(jī)加載的類信息乡数,常量椭蹄,靜態(tài)變量,編譯器編譯后的代碼瞳脓。也就是常說的永久代。

永久代的大小可以用-XX:MaxPermSize去設(shè)置澈侠。

運(yùn)行時(shí)常量池:方法區(qū)的一部分劫侧。存放編譯期生成的各種字面量和符號(hào)引用。字面量就是指這個(gè)量本身哨啃。比如字面量2烧栋,就是指2.

運(yùn)行時(shí)常量池有一個(gè)重要特性就是動(dòng)態(tài)性。常量不一定只有編譯期才能產(chǎn)生拳球,運(yùn)行期間也可能將新的常量放入常量池审姓。詳情可見String類的

intern()方法。

此處推薦這篇博客祝峻,對(duì)intern()方法介紹的挺清楚的魔吐。

幾張圖輕松理解String.intern() - 程序老兵的博客 - CSDN博客

直接內(nèi)存:它不是虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)的一部分,但也頻繁的被使用莱找。直接內(nèi)存不會(huì)受到j(luò)ava堆大小的限制酬姆,但是會(huì)受到本機(jī)總內(nèi)存的限制。

GC過程

GC分為新生代GC(minor gc)和老年代GC(full gc)奥溺。新生代GC的頻率遠(yuǎn)遠(yuǎn)高于老年代辞色。而且

新生代GC的速度會(huì)比老年代的GC速度快10倍以上。根源在于新生代和老年代使用的GC算法不同浮定。讀者們可以去仔細(xì)思考下相满。新生代/老年代大小默認(rèn)為1:2层亿。

新生代GC過程

? ? 新生代里可細(xì)分為Eden,From survivor,To survivor等空間。當(dāng)我們需要給對(duì)象分配內(nèi)存的時(shí)候立美,首先我們會(huì)在Eden區(qū)為對(duì)象分配內(nèi)存匿又,當(dāng)Eden區(qū)內(nèi)存不足時(shí),會(huì)發(fā)生minor gc悯辙,此時(shí)會(huì)把仍然存活的對(duì)象放到From survivor琳省,并給對(duì)象標(biāo)記存活次數(shù)1;然后當(dāng)Eden區(qū)再次被用完后躲撰,對(duì)Eden區(qū)和From survivor區(qū)篩選出存活的對(duì)象针贬,放到To survivor區(qū),清空Eden區(qū)和From survivor區(qū)拢蛋,存活次數(shù)加1桦他,之前存活的就是2了。

? ? 以此類推谆棱,默認(rèn)是當(dāng)存活次數(shù)到達(dá)15次(可配置)的時(shí)候快压,把這個(gè)對(duì)象存入老年代中。同時(shí)也可以看到垃瞧,F(xiàn)rom survivor,To survivor區(qū)始終有一個(gè)是空置的蔫劣。所以新生代使用的只有9/10的空間。

然而大家可以思考一下个从。Eden區(qū)和survivor區(qū)的大小為8:1脉幢,那么發(fā)生minor gc后如果存活的對(duì)象

的大小比survivor區(qū)還要大。這個(gè)時(shí)候會(huì)怎么處理嗦锐?

? ? 這里需要引入一個(gè)叫“內(nèi)存分配擔(dān)保機(jī)制”的概念嫌松。就是當(dāng)存活的對(duì)象連survivor區(qū)都放不下的時(shí)候,這部分放不下的對(duì)象會(huì)直接進(jìn)入老年代奕污。老年代是擔(dān)保人萎羔。老年代進(jìn)行擔(dān)保,前提是老年代還有剩余空間碳默。但是每次存活下來的對(duì)象大小是不確定的贾陷。所以只好取之前每次存儲(chǔ)到老年代的對(duì)象大小的平均值。如果大于平均值嘱根,那么直接full gc昵宇。但是為了避免頻繁full gc,仍然會(huì)開啟handlepromotionfailure配置儿子。如下圖



老年代GC過程:

老年代采用了標(biāo)記整理瓦哎,標(biāo)記清楚的算法。老年代會(huì)把仍然存活的對(duì)象都整理統(tǒng)一放到一邊。整理完成后就會(huì)清楚掉邊界外的對(duì)象蒋譬。這樣就避免了產(chǎn)生大量的內(nèi)存碎片的問題割岛。但是整理算法相較于新生代采用的復(fù)制算法,復(fù)雜程度肯定更高犯助。這也導(dǎo)致了full gc的速度要遠(yuǎn)遠(yuǎn)慢于minor gc癣漆。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市剂买,隨后出現(xiàn)的幾起案子惠爽,更是在濱河造成了極大的恐慌,老刑警劉巖瞬哼,帶你破解...
    沈念sama閱讀 222,807評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件婚肆,死亡現(xiàn)場離奇詭異,居然都是意外死亡坐慰,警方通過查閱死者的電腦和手機(jī)较性,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來结胀,“玉大人赞咙,你說我怎么就攤上這事≡愀郏” “怎么了攀操?”我有些...
    開封第一講書人閱讀 169,589評(píng)論 0 363
  • 文/不壞的土叔 我叫張陵,是天一觀的道長秸抚。 經(jīng)常有香客問我速和,道長,這世上最難降的妖魔是什么耸别? 我笑而不...
    開封第一講書人閱讀 60,188評(píng)論 1 300
  • 正文 為了忘掉前任健芭,我火速辦了婚禮县钥,結(jié)果婚禮上秀姐,老公的妹妹穿的比我還像新娘。我一直安慰自己若贮,他們只是感情好省有,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,185評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著谴麦,像睡著了一般蠢沿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上匾效,一...
    開封第一講書人閱讀 52,785評(píng)論 1 314
  • 那天舷蟀,我揣著相機(jī)與錄音,去河邊找鬼。 笑死野宜,一個(gè)胖子當(dāng)著我的面吹牛扫步,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播匈子,決...
    沈念sama閱讀 41,220評(píng)論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼河胎,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了虎敦?” 一聲冷哼從身側(cè)響起游岳,我...
    開封第一講書人閱讀 40,167評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎其徙,沒想到半個(gè)月后胚迫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,698評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡擂橘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,767評(píng)論 3 343
  • 正文 我和宋清朗相戀三年晌区,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片通贞。...
    茶點(diǎn)故事閱讀 40,912評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡朗若,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出昌罩,到底是詐尸還是另有隱情哭懈,我是刑警寧澤,帶...
    沈念sama閱讀 36,572評(píng)論 5 351
  • 正文 年R本政府宣布茎用,位于F島的核電站遣总,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏轨功。R本人自食惡果不足惜旭斥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,254評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望古涧。 院中可真熱鬧垂券,春花似錦、人聲如沸羡滑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽柒昏。三九已至凳宙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間职祷,已是汗流浹背氏涩。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評(píng)論 1 274
  • 我被黑心中介騙來泰國打工届囚, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人是尖。 一個(gè)月前我還...
    沈念sama閱讀 49,359評(píng)論 3 379
  • 正文 我出身青樓奖亚,卻偏偏與公主長得像,于是被迫代替她去往敵國和親析砸。 傳聞我的和親對(duì)象是個(gè)殘疾皇子昔字,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,922評(píng)論 2 361

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

  • jvm原理 Java虛擬機(jī)是整個(gè)java平臺(tái)的基石作郭,是java技術(shù)實(shí)現(xiàn)硬件無關(guān)和操作系統(tǒng)無關(guān)的關(guān)鍵環(huán)節(jié),是java...
    AI喬治閱讀 17,254評(píng)論 21 486
  • JVM架構(gòu) 當(dāng)一個(gè)程序啟動(dòng)之前弦疮,它的class會(huì)被類裝載器裝入方法區(qū)(Permanent區(qū))夹攒,執(zhí)行引擎讀取方法區(qū)的...
    cocohaifang閱讀 1,673評(píng)論 0 7
  • http://www.cnblogs.com/angeldevil/p/3801189.html值得一看 Clas...
    snail_knight閱讀 1,428評(píng)論 1 0
  • 1 CPU和內(nèi)存的交互 了解jvm內(nèi)存模型前,了解下cpu和計(jì)算機(jī)內(nèi)存的交互情況胁塞∮匠ⅲ【因?yàn)镴ava虛擬機(jī)內(nèi)存模型定義...
    Garwer閱讀 369,475評(píng)論 54 550
  • 內(nèi)存溢出和內(nèi)存泄漏的區(qū)別 內(nèi)存溢出:out of memory,是指程序在申請(qǐng)內(nèi)存時(shí)啸罢,沒有足夠的內(nèi)存空間供其使用编检,...
    Aimerwhy閱讀 744評(píng)論 0 1