JVM內(nèi)存結(jié)構(gòu)

JVM架構(gòu)

JVM = 類加載器(classloader) + 執(zhí)行引擎(execution engine) + 運行時數(shù)據(jù)區(qū)(runtime data area)


jvm架構(gòu).jpg
運行時數(shù)據(jù)區(qū).jpg

內(nèi)存分類

按空間劃分為兩類:堆內(nèi)存(Heap) 筒繁、非堆內(nèi)存(NonHeap)

堆內(nèi)存(Heap)

堆內(nèi)存.jpg
  • 堆是Java 虛擬機所管理的內(nèi)存中最大的一塊阳准,默認(rèn)為物理內(nèi)存1/4大小
  • 堆是被所有線程共享的區(qū)域叶撒,在虛擬機啟動時創(chuàng)建
  • 堆里面存放的都是對象的實例(new 出來的對象都存在堆中)
  • 我們平常所說的垃圾回收,主要回收的就是堆區(qū)
  • 默認(rèn)的悟民,新生代 ( Young ) 與老年代 ( Old ) 的比例的值為 1:2
  • 默認(rèn)的丸卷,Eden : From : To = 8 : 1 : 1 ( 可以通過參數(shù) –XX:SurvivorRatio 來設(shè)定 )
Thread Local Allocation Buffer (TLAB挺举,線程本地分配緩沖區(qū))
  • 占用 Eden 區(qū)(缺省 Eden 的1%)弱恒,默認(rèn)開啟,線程私有
  • 優(yōu)化多線程堆空間分配對象指針碰撞問題

非堆內(nèi)存(NonHeap)

非堆內(nèi)存.jpg
Metaspace
  • JAVA8以后使用Metaspace替代了PermGen(永久代)棋恼,將元數(shù)據(jù)移動到了非堆內(nèi)存中返弹。默認(rèn)為物理內(nèi)存的1/64大小
  • 當(dāng)一個類被加載時,它的類加載器會負(fù)責(zé)在 Metaspace 中分配空間用于存放這個類的元數(shù)據(jù)
  • 只有當(dāng)這個類加載器加載的所有類都沒有存活的對象爪飘,并且沒有到達(dá)這些類和類加載器的引用時义起,相應(yīng)的 Metaspace 空間才會被 GC 釋放
  • 釋放 Metaspace 的空間,并不意味著將這部分空間還給系統(tǒng)內(nèi)存师崎,這部分空間通常會被 JVM 保留下來
  • Metaspace 可能在兩種情況下觸發(fā) GC:Metaspace需要擴容時默终、達(dá)到MaxMetaspaceSize時,所以通常把-XX:MetaspaceSize和-XX:MaxMetaspaceSize設(shè)置為相同的值(Metaspace默認(rèn)大小只有21MB)
Compressed Class Space
  • 壓縮指針犁罩,指的是在 64 位的機器上齐蔽,使用 32 位的指針來訪問數(shù)據(jù)(堆中的對象或 Metaspace 中的元數(shù)據(jù))的一種方式
  • 它需要被分配一個連續(xù)的地址空間,因此在GC后釋放的空間會被JVM保留床估,一定不會還給物理內(nèi)存
  • 默認(rèn)大小是1G含滴,但如果設(shè)置了-XX:MaxMetaspaceSize,則它的大小不會超過MaxMetaspaceSize
Direct Memory
  • NIO(New Input/Output)類丐巫,引入了一種基于通道(Channel)與緩沖區(qū)(Buffer)的 I/O 方式谈况,它可以使用 native 函數(shù)庫直接分配堆外內(nèi)存,然后通過一個存儲在Java堆中的 DirectByteBuffer 對象作為這塊內(nèi)存的引用進行操作
  • 可以幫助JAVA實現(xiàn)零拷貝
  • 默認(rèn)大小為堆內(nèi)存大小递胧,可通過-XX:MaxDirectMemorySize設(shè)置
  • 不會被GC碑韵,使用時要注意釋放

線程共享與私有

線程共享與私有.jpg

堆外內(nèi)存使用指標(biāo)

usedcapacity 缎脾、committed祝闻、reserved

  • committed、reserved
    committedreserved并不純粹是JVM的概念赊锚,它和操作系統(tǒng)相關(guān)治筒。
    reserved是指,操作系統(tǒng)已經(jīng)為該進程“保留”的舷蒲。所謂的保留耸袜,更加接近一種記賬的概念,就是操作系統(tǒng)承諾說一大塊連續(xù)的內(nèi)存已經(jīng)是你這個進程的了牲平。那么實際上這一大塊內(nèi)存有沒有真實對應(yīng)的物理內(nèi)存堤框,這時是不知道的,等進程committed的時候,進程真的要用這個連續(xù)地址空間的時候蜈抓,操作系統(tǒng)才會分配真正的內(nèi)存启绰。所以,這也就是意味著沟使,這個過程會失敗委可。

  • used、capacity
    比如創(chuàng)建了一個可以存放20個元素的ArrayList腊嗡,但是我實際上只放了10個元素着倾,那么capacity就是20,而size就是10燕少,這里的size和used就是一個概念卡者。

Netty直接內(nèi)存溢出

  • 如果有手工分配了DataBuffer但是沒有釋放的時候,Netty會報警ByteBuf.release()沒有調(diào)用客们。
  • 如果直接內(nèi)存被占滿無法繼續(xù)分配到內(nèi)存空間崇决,會報出OutOfDirectMemoryError的異常,大量的請求無法獲取內(nèi)存會導(dǎo)致應(yīng)用掛掉底挫,無法訪問任何接口恒傻。
LEAK.jpg
OODM.jpg

常見調(diào)優(yōu)參數(shù)

參數(shù)名稱 含義 默認(rèn)值 說明
-Xms ? 初始堆大小 ?????????? ? 物理內(nèi)存的1/64 ?????????? 默認(rèn)空余堆內(nèi)存小于40%時(MinHeapFreeRatio),堆增大到-Xmx的值
-Xmx 最大堆大小 物理內(nèi)存的1/4 默認(rèn)空余堆內(nèi)存大于70%時(MaxHeapFreeRatio)建邓,堆減小到-Xms的值
-Xmn 年輕代大小 堆內(nèi)存的1/3 此處的大小是eden+ 2 survivor space碌冶,增大年輕代后,將會減小年老代大小
-Xss 每個線程的堆棧大小 1M
-XX:NewRatio 年輕代與年老代的比值 2 -XX:NewRatio=4表示年輕代與年老代所占比值為1:4,年輕代占整個堆棧的1/5,當(dāng)Xms=Xmx并且設(shè)置了Xmn的情況下涝缝,該參數(shù)不需要進行設(shè)置
-XX:MetaspaceSize 元空間初始大小 21M 元空間的大小達(dá)到這個值時扑庞,會觸發(fā)Full GC并會卸載沒有用的類
-XX:MaxMetaspaceSize 元空間最大可分配大小 物理內(nèi)存的1/64
-XX:MaxDirectMemorySize 直接內(nèi)存最大可分配大小 與堆內(nèi)存相同
  • 應(yīng)用可分配的最大內(nèi)存

[-Xmx] + 線程數(shù)量*[-Xss] + [-XX:MaxMetaspaceSize] + [-XX:MaxDirectMemorySize]


垃圾回收(GC)

有不少人把這項技術(shù)當(dāng)作Java語言的伴生產(chǎn)物。事實上,垃圾收集的歷史遠(yuǎn)遠(yuǎn)比Java久遠(yuǎn),在1960年誕生于麻省理工學(xué)院的Lisp是第一門開始使用內(nèi)存動態(tài)分配和垃圾收集技術(shù)的語言躯肌。

GC重點
  • 程序計數(shù)器、虛擬機棧栅隐、本地方法棧3個區(qū)域隨線程而生,隨線程而滅玩徊,因此這幾個區(qū)域的內(nèi)存分配和回收都具備確定性租悄,不需要過多考慮如何回收的問題,當(dāng)方法結(jié)束或者線程結(jié)束時恩袱,內(nèi)存自然就跟隨著回收了泣棋。
  • 而Java堆和方法區(qū)(元數(shù)據(jù)區(qū))這兩個區(qū)域則有著很顯著的不確定性,只有處于運行期間畔塔,我們才能知道程序究竟會創(chuàng)建哪些對象潭辈,創(chuàng)建多少個對象鸯屿,這部分內(nèi)存的分配和回收是動態(tài)的。垃圾收集器所關(guān)注的正是這部分內(nèi)存該如何管理把敢。
可達(dá)性分析法

當(dāng)前主流的商用程序語言(Java寄摆、C#,上溯至前面提到的古老的Lisp)的內(nèi)存管理子系統(tǒng)修赞,都是通過可達(dá)性分析(Reachability Analysis)算法來判定對象是否存活的婶恼。

可達(dá)性分析法.jpg

在Java技術(shù)體系里面,固定可作為GC Roots的對象包括以下幾種:

  • 在虛擬機棧(棧幀中的本地變量表)中引用的對象柏副,譬如各個線程被調(diào)用的方法堆棧中使用到的參數(shù)熙尉、局部變量、臨時變量等
  • 在方法區(qū)中類靜態(tài)屬性引用的對象搓扯,譬如Java類的引用類型靜態(tài)變量。
  • 在方法區(qū)中常量引用的對象包归,譬如字符串常量池(String Table)里的引用
  • 在本地方法棧中JNI(即通常所說的Native方法)引用的對象
  • Java虛擬機內(nèi)部的引用锨推,如基本數(shù)據(jù)類型對應(yīng)的Class對象,一些常駐的異常對象(比如NullPointExcepiton公壤、OutOfMemoryError)等换可,還有系統(tǒng)類加載器
  • 所有被同步鎖(synchronized關(guān)鍵字)持有的對象
  • 反映Java虛擬機內(nèi)部情況的JMXBean、JVMTI中注冊的回調(diào)厦幅、本地代碼緩存等
分代收集理論

當(dāng)前商業(yè)虛擬機的垃圾收集器沾鳄,大多數(shù)都遵循了“分代收集”(Generational Collection)[1]的理論進行設(shè)計,分代收集名為理論确憨,實質(zhì)是一套符合大多數(shù)程序運行實際情況的經(jīng)驗法則译荞,它建立在兩個分代假說之上:

  • 弱分代假說(Weak Generational Hypothesis):絕大多數(shù)對象都是朝生夕滅的
  • 強分代假說(Strong Generational Hypothesis):熬過越多次垃圾收集過程的對象就越難以消亡

這兩個分代假說共同奠定了多款常用的垃圾收集器的一致的設(shè)計原則:

  • 收集器應(yīng)該將Java堆劃分出不同的區(qū)域,然后將回收對象依據(jù)其年齡(年齡即對象熬過垃圾收集過程的次數(shù))分配到不同的區(qū)域之中存儲

在一次次只局限于新生代區(qū)域內(nèi)的收集中休弃,新生代中的對象是完全有可能被老年代所引用的吞歼,因此對分代收集理論添加第三條經(jīng)驗法則:

  • 跨代引用假說(Intergenerational Reference Hypothesis):跨代引用相對于同代引用來說僅占極少數(shù)

不應(yīng)再為了少量的跨代引用去掃描整個老年代,也不必浪費空間專門記錄每一個對象是否存在及存在哪些跨代引用塔猾,只需在新生代上建立一個全局的數(shù)據(jù)結(jié)構(gòu)記憶集(Remembered Set)篙骡,把老年代劃分成若干小塊,標(biāo)識出老年代的哪一塊內(nèi)存會存在跨代引用丈甸。

各階段GC名詞:

  • 新生代收集(Minor GC/Young GC):指目標(biāo)只是新生代的垃圾收集
  • 老年代收集(Major GC/Old GC):指目標(biāo)只是老年代的垃圾收集糯俗。目前只有CMS收集器會有單獨收集老年代的行為。Major GC在不同的資料上常有不同所指睦擂,需要按照上下文區(qū)分到底是指老年代收集還是整堆收集
  • 整堆收集(Full GC):收集整個Java堆和方法區(qū)(元數(shù)據(jù)區(qū))的垃圾收集得湘。
堆內(nèi)存使用流程
對象申請內(nèi)存流程.jpg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市顿仇,隨后出現(xiàn)的幾起案子忽刽,更是在濱河造成了極大的恐慌天揖,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件跪帝,死亡現(xiàn)場離奇詭異今膊,居然都是意外死亡,警方通過查閱死者的電腦和手機伞剑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門斑唬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人黎泣,你說我怎么就攤上這事恕刘。” “怎么了抒倚?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵褐着,是天一觀的道長。 經(jīng)常有香客問我托呕,道長含蓉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任项郊,我火速辦了婚禮馅扣,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘着降。我一直安慰自己差油,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布任洞。 她就那樣靜靜地躺著蓄喇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪交掏。 梳的紋絲不亂的頭發(fā)上公罕,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天,我揣著相機與錄音耀销,去河邊找鬼楼眷。 笑死,一個胖子當(dāng)著我的面吹牛熊尉,可吹牛的內(nèi)容都是我干的罐柳。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼狰住,長吁一口氣:“原來是場噩夢啊……” “哼张吉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起催植,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤肮蛹,失蹤者是張志新(化名)和其女友劉穎勺择,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體伦忠,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡省核,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了昆码。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片气忠。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖赋咽,靈堂內(nèi)的尸體忽然破棺而出旧噪,到底是詐尸還是另有隱情,我是刑警寧澤脓匿,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布淘钟,位于F島的核電站,受9級特大地震影響陪毡,放射性物質(zhì)發(fā)生泄漏米母。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一缤骨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧尺借,春花似錦绊起、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至栅表,卻和暖如春笋鄙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背怪瓶。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工萧落, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人洗贰。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓找岖,卻偏偏與公主長得像,于是被迫代替她去往敵國和親敛滋。 傳聞我的和親對象是個殘疾皇子许布,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,486評論 2 348

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