2020-12-20 JVM -- 運行時數(shù)據(jù)區(qū)與內(nèi)存模型

開篇問題:

  1. 一句話描述類加載過程锈死?

    類加載過程實際是將Java文件編譯為class文件并裝載到JVM中最終解析為01機器代碼供服務(wù)器進行的過程午阵,涉及到的過程包括:編譯、裝載鸳址、鏈接戳葵、初始化就乓、使用、卸載6個過程拱烁,其中各個過程的作用分別是:

    • 編譯:通過javac命令將Java文件轉(zhuǎn)換成class文件生蚁。
    • 裝載:查找并加載class文件。
    • 鏈接:包括:驗證戏自、準(zhǔn)備邦投、解析。
      1. 驗證:通過對二進制流的內(nèi)容進行校驗來檢查是否符合JVM的要求規(guī)范以及是否會對程序運行時是否會對JVM造成危害浦妄。其中包括:文件格式驗證 --> 元數(shù)據(jù)驗證 --> 字節(jié)碼驗證 --> 符號引用驗證尼摹。
      2. 準(zhǔn)備:在方法區(qū)中為類變量(靜態(tài)變量)分配內(nèi)存并設(shè)置系統(tǒng)默認(rèn)初始值。
      3. 解析:將方法區(qū)中的符號引用轉(zhuǎn)變成直接或引用剂娄,并對解析結(jié)構(gòu)進行緩存蠢涝。
    • 初始化:調(diào)用構(gòu)造方法對類變量賦予程序中設(shè)置的值。
    • 使用:
    • 卸載:類卸載的三個條件必須都滿足才能進行卸載阅懦,一般情況下
  2. 詳細(xì)描述對象的內(nèi)存布局每一個部分干了什么和二,用到了什么技術(shù)?

對象內(nèi)存布局包括:對象頭耳胎、實例數(shù)據(jù)惯吕、對其填充三部分。其中

對象頭包含:Mark Word怕午、Class Pointer废登、Length。

  • Mark Word:一系列標(biāo)志位郁惜,包括:哈希碼堡距、分代年齡、鎖狀態(tài)標(biāo)志等,其中哈希碼用到了大端存儲技術(shù)羽戒,便于數(shù)據(jù)類型的符號判斷)
  • Class Pointer:指向?qū)ο髮?yīng)類的內(nèi)存地址缤沦,其中引用定位到對象的方式包括:句柄池訪問直接訪問易稠。
    1. 句柄池訪問:使用句柄訪問對象缸废,會在堆中開辟一塊內(nèi)存作為句柄池,句柄中儲存了對象實例數(shù)據(jù) 的內(nèi)存地址驶社,訪問類型數(shù)據(jù)的內(nèi)存地址企量,優(yōu)點:reference存儲的是穩(wěn)定的句柄地址,在對象被移動時只會改變句柄中的實例數(shù)據(jù)指針衬吆,而reference本身不需要改變梁钾;缺點:增加了一次指針定位的時間開銷绳泉。
    2. 直接訪問:指reference中直接儲存對象在heap中的內(nèi)存地址逊抡,但對應(yīng)的類型數(shù)據(jù)訪問地址需要 在實例中存儲。優(yōu)點:節(jié)省了一次指針定位的開銷零酪;缺點:在對象被移動時冒嫡,reference本身需要被修改。
  • Length:數(shù)據(jù)對象特有四苇,用于記錄數(shù)組長度孝凌。

實例數(shù)據(jù)包含:包含了對象的所有成員變量,大小由變量本身的類型決定月腋,用到的技術(shù)-- 指針壓縮技術(shù)作用包括:減少GC次數(shù)蟀架,提供CPU的OOP緩存。
對其填充的作用:為了保證對象的大小為8字節(jié)的整數(shù)倍榆骚,對其填充技術(shù)的作用是提高CPU訪問數(shù)據(jù)的效率片拍。

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

CPU內(nèi)存模型

通過CPU與主存的關(guān)系可以推斷出JVM是如何跟服務(wù)器的CPU和內(nèi)存進行交互的 – java是多線程機制,當(dāng)多個任務(wù)執(zhí)行(類比我們的CPU運算核心)對同一塊內(nèi)存(類比:主存)數(shù)據(jù)進行操作時(PS:線程共享)必然會發(fā)生數(shù)據(jù)不一致的情況,這個時候需要有一塊區(qū)域或者一種操作(類比:協(xié)議)保證數(shù)據(jù)的一致性妓肢。而每個線程又有自己單獨的工作內(nèi)存(類比高速緩沖區(qū)),當(dāng)我們線程進行運作時,數(shù)據(jù)肯定會從JVM主存拷貝到線程自己的工作內(nèi)存,然后再進行操作捌省。

運行時數(shù)據(jù)區(qū)數(shù)據(jù)結(jié)構(gòu).png

方法區(qū)

方法區(qū)是被線程共享的Non-Heap(非堆) 內(nèi)存區(qū)域,用于存儲已被虛擬機加載的類信息碉钠、常量纲缓、靜態(tài)變量、即時編譯器編譯后的代碼等數(shù)據(jù)喊废,在虛擬機啟動時創(chuàng)建祝高。

注意:

JVM運行時數(shù)據(jù)區(qū)是一種規(guī)范,真正的實現(xiàn)
方法區(qū)在JDK 8中就是Metaspace污筷,在JDK6或7中就是Perm Space

堆是Java虛擬機所管理內(nèi)存中最大的一塊工闺,在虛擬機啟動時創(chuàng)建,被所有線程共享。其中 Java對象實例以及數(shù)組都在堆上分配斤寂。

虛擬機棧

問題:那一個線程執(zhí)行的狀態(tài)如何維護?一個線程可以執(zhí)行多 少個方法?這樣的關(guān)系怎么維護呢?

  • ?虛擬機棧是一個線程執(zhí)行的區(qū)域耿焊,保存著一個線程中方法的調(diào)用狀態(tài)。換句話說遍搞,一個Java線程的運行狀態(tài)罗侯,由一個虛擬機棧來保存,所以虛擬機椣常肯定是線程私有的钩杰,獨有的,隨著線程的創(chuàng)建而創(chuàng)建诊县。
  • 每一個被線程執(zhí)行的方法讲弄,為該棧中的棧幀,即每個方法對應(yīng)一個棧幀依痊。 調(diào)用一個方法避除,就會向棧中壓入一個棧幀;一個方法調(diào)用完成,就會把該棧幀從棧中彈出胸嘁。
棧幀:

棧幀:每個棧幀對應(yīng)一個被調(diào)用的方法瓶摆,可以理解為一個方法的運行空間

棧幀中包括局部變量 表性宏、操作數(shù)棧群井、動態(tài)鏈接、方法返回地址和即時信息毫胜。

?局部變量 表:方法中定義的局部變量以及方法的參數(shù)存放在這張表中书斜, 局部變量表中的變量不可直接使用,如需要使用的話酵使,必須通過相關(guān)指令將其加載至操作數(shù)棧中作為操作數(shù)使用荐吉。

操作數(shù) 棧:以壓棧和出棧的方式存儲操作數(shù)的。如 1+1 兩個1存儲在局部變量 表中凝化, 1+1這個操作在操作數(shù)棧中完成稍坯。

動態(tài)鏈接:每個棧幀都包含一個指向運行時常量池中該棧幀所屬方法的引用,持有這個引用是為了支持方法調(diào)用過程中的動態(tài)連接(符號引用編程直接引用)搓劫。因為類加載機制 僅僅是將本文件的符號引用變成直接引用 瞧哟,當(dāng)遇到多態(tài)的調(diào)用時,只能通過運行來確定子類對接的引用是哪一個枪向。

方法返回地址:當(dāng)一個方法開始執(zhí)行后,只有兩種方式可以退出勤揩,一種是遇到方法返回的字節(jié)碼指令;一種是遇 見異常,并且這個異常沒有在方法體內(nèi)得到處理秘蛔。

本地方法棧

當(dāng)前線程執(zhí)行的方法是Native類型的陨亡,這些方法就會在本地方法棧中執(zhí)行

思考:在Java方法執(zhí)行的時候如何調(diào)用native的方法呢?

通過動態(tài)鏈接來進行調(diào)用傍衡。


動態(tài)鏈接.png

程序計數(shù)器

作用:是記錄當(dāng)前線程的執(zhí)行位置,線程私有负蠕。

如果線程正在執(zhí)行Java方法蛙埂,則計數(shù)器記錄的是正在執(zhí)行的虛擬機字節(jié)碼指令的地址;

如果正在執(zhí)行的是Native方法,則這個計數(shù)器為空遮糖。

除了上面五塊內(nèi)存之外,其實我們的JVM還會使用到其他兩塊內(nèi)存

直接內(nèi)存(Direct Memory)

并不是虛擬機運行時數(shù)據(jù)區(qū)的一部分绣的,也不是JVM規(guī)范中定義的內(nèi)存區(qū)域,但是這部分內(nèi)存也被頻 繁地使用欲账,而且也可能導(dǎo)致OutOfMemoryError 異常出現(xiàn)屡江,所以我們放到這里一起講解。在JDK 1.4 中新加入了NIO(New Input/Output)類赛不,引入了一種基于通道(Channel)與緩沖區(qū) (Buffer)的I/O 方式惩嘉,它可以使用Native 函數(shù)庫直接分配堆外內(nèi)存,然后通過一個存儲在Java 堆 里面的DirectByteBuffer 對象作為這塊內(nèi)存的引用進行操作踢故。這樣能在一些場景中顯著提高性能文黎, 因為避免了在Java 堆和Native 堆中來回復(fù)制數(shù)據(jù)。

本機直接內(nèi)存的分配不會受到Java 堆大小的限制畴椰,但是臊诊,既然是內(nèi)存,則肯定還是會受到本機總 內(nèi)存的大小及處理器尋址空間的限制斜脂。因此在分配JVM空間的時候應(yīng)該考慮直接內(nèi)存所帶來的影 響,特別是應(yīng)用到NIO的場景触机。

其他內(nèi)存:

Code Cache:**JVM本身是個本地程序帚戳,還需要其他的內(nèi)存去完成各種基本任務(wù),比如儡首,JIT 編譯器在運行時對熱點方法進行編譯片任,就會將編譯后的方法儲存在Code Cache里面;GC等 功能。需要運行在本地線程之中蔬胯,類似部分都需要占用內(nèi)存空間对供。這些是實現(xiàn)JVM JIT等功能 的需要,但規(guī)范中并不涉及

其中椃毡簦可以指向堆 case: Object obj=new Object()

方法區(qū)指向堆 case: private static Object obj=new Object();

堆指向方法區(qū) case: Class類對象指向它的元數(shù)據(jù)产场。 new Object().getClass();

Java對象內(nèi)存模型

一個Java對象在內(nèi)存中包括3個部分:對象頭、實例數(shù)據(jù)和對齊填充舞竿。


Java對象內(nèi)存布局.png
內(nèi)存模型設(shè)計之–大小端存儲

小端存儲:便于數(shù)據(jù)之間的類型轉(zhuǎn)換京景,例如:long類型轉(zhuǎn)換為int類型時,高地址部分的數(shù)據(jù)可以 直接截掉骗奖。

大端存儲:便于數(shù)據(jù)類型的符號判斷确徙,因為最低地址位數(shù)據(jù)即為符號位醒串,可以直接判斷數(shù)據(jù)的正 負(fù)號。

內(nèi)存模型設(shè)計之–Class Pointer

引用定位到對象的方式有兩種鄙皇,一種叫句柄池訪問芜赌,一種叫直接訪問


句柄池訪問對象.png
直接指針訪問對象.png

區(qū)別:

句柄池:

使用句柄訪問對象,會在堆中開辟一塊內(nèi)存作為句柄池伴逸,句柄中儲存了對象實例數(shù)據(jù)(屬性值結(jié)構(gòu)體) 的內(nèi)存地址较鼓,訪問類型數(shù)據(jù)的內(nèi)存地址(類信息,方法類型信息)违柏,對象實例數(shù)據(jù)一般也在heap中開 辟博烂,類型數(shù)據(jù)一般儲存在方法區(qū)中。

優(yōu)點:reference存儲的是穩(wěn)定的句柄地址漱竖,在對象被移動(垃圾收集時移動對象是非常普遍的行為) 時只會改變句柄中的實例數(shù)據(jù)指針禽篱,而reference本身不需要改變。

缺點:增加了一次指針定位的時間開銷馍惹。 直接訪問:

直接指針訪問方式指reference中直接儲存對象在heap中的內(nèi)存地址躺率,但對應(yīng)的類型數(shù)據(jù)訪問地址需要 在實例中存儲。

優(yōu)點:節(jié)省了一次指針定位的開銷万矾。 缺點:在對象被移動時(如進行GC后的內(nèi)存重新排列)悼吱,reference本身需要被修改

內(nèi)存模型設(shè)計之–指針壓縮

指針壓縮的目的:

  1. 為了保證CPU普通對象指針(oop)緩存
  2. 為了減少GC的發(fā)生,因為指針不壓縮是8字節(jié)良狈,這樣在64位操作系統(tǒng)的堆上其他資源空間就少了后添。

64位操作系統(tǒng)中 內(nèi)存 > 4G 默認(rèn)開啟指針壓縮技術(shù),內(nèi)存< 4G薪丁,默認(rèn)是32位系統(tǒng)默認(rèn)不開啟遇西。內(nèi)存 > 32G 指針壓縮失效。所以我們通常在部署服務(wù)時严嗜,JVM內(nèi)存不要超過32G粱檀,因為超過32G就無法開啟 指針壓縮了。

內(nèi)存 > 32G指針壓縮失效的原因是:4G*8 = 32G

32位系統(tǒng)的CPU 最大支持2^32 = 4G ,如果是64位系統(tǒng)漫玄,最大支持 2^64茄蚯, 但是對其填充是按照8字節(jié)進行填充,指針壓縮可以理解為在32位系統(tǒng)在64位上面使用睦优,因為32位系統(tǒng)的CPU尋址空間最大支持4G渗常,對其填充*8 = 32G,這就是內(nèi)存>32G指針壓縮失效的原因刨秆。

關(guān)閉指針壓縮 : -XX:+UseCompressedOops

內(nèi)存模型設(shè)計之–對齊填充

對齊填充的意義是提高CPU訪問數(shù)據(jù)的效率凳谦,主要針對會存在該實例對象數(shù)據(jù)跨內(nèi)存地址區(qū)域存儲的情況。

例如:在沒有對齊填充的情況下衡未,內(nèi)存地址存放情況如下:


對其填充反例.png

因為處理器只能0x00-0x07尸执,0x08-0x0F這樣讀取數(shù)據(jù)家凯,所以當(dāng)我們想獲取這個long型的數(shù)據(jù)時,處理 器必須要讀兩次內(nèi)存如失,第一次(0x00-0x07)绊诲,第二次(0x08-0x0F),然后將兩次的結(jié)果才能獲得真正的數(shù)值褪贵。

那么在有對齊填充的情況下掂之,內(nèi)存地址存放情況是這樣的:


對其填充正例.png

現(xiàn)在處理器只需要直接一次讀取(0x08-0x0F)的內(nèi)存地址就可以獲得我們想要的數(shù)據(jù)了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載脆丁,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者世舰。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市槽卫,隨后出現(xiàn)的幾起案子跟压,更是在濱河造成了極大的恐慌,老刑警劉巖歼培,帶你破解...
    沈念sama閱讀 223,002評論 6 519
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件震蒋,死亡現(xiàn)場離奇詭異,居然都是意外死亡躲庄,警方通過查閱死者的電腦和手機查剖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,357評論 3 400
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來噪窘,“玉大人笋庄,你說我怎么就攤上這事⌒Ю溃” “怎么了无切?”我有些...
    開封第一講書人閱讀 169,787評論 0 365
  • 文/不壞的土叔 我叫張陵,是天一觀的道長丐枉。 經(jīng)常有香客問我,道長掘托,這世上最難降的妖魔是什么瘦锹? 我笑而不...
    開封第一講書人閱讀 60,237評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮闪盔,結(jié)果婚禮上弯院,老公的妹妹穿的比我還像新娘。我一直安慰自己泪掀,他們只是感情好听绳,可當(dāng)我...
    茶點故事閱讀 69,237評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著异赫,像睡著了一般椅挣。 火紅的嫁衣襯著肌膚如雪头岔。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,821評論 1 314
  • 那天鼠证,我揣著相機與錄音峡竣,去河邊找鬼。 笑死量九,一個胖子當(dāng)著我的面吹牛适掰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播荠列,決...
    沈念sama閱讀 41,236評論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼类浪,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了肌似?” 一聲冷哼從身側(cè)響起费就,我...
    開封第一講書人閱讀 40,196評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎锈嫩,沒想到半個月后受楼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,716評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡呼寸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,794評論 3 343
  • 正文 我和宋清朗相戀三年艳汽,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片对雪。...
    茶點故事閱讀 40,928評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡河狐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出瑟捣,到底是詐尸還是另有隱情馋艺,我是刑警寧澤,帶...
    沈念sama閱讀 36,583評論 5 351
  • 正文 年R本政府宣布迈套,位于F島的核電站捐祠,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏桑李。R本人自食惡果不足惜踱蛀,卻給世界環(huán)境...
    茶點故事閱讀 42,264評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望贵白。 院中可真熱鬧率拒,春花似錦、人聲如沸禁荒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,755評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽呛伴。三九已至勃痴,卻和暖如春谒所,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背召耘。 一陣腳步聲響...
    開封第一講書人閱讀 33,869評論 1 274
  • 我被黑心中介騙來泰國打工百炬, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人污它。 一個月前我還...
    沈念sama閱讀 49,378評論 3 379
  • 正文 我出身青樓剖踊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親衫贬。 傳聞我的和親對象是個殘疾皇子德澈,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,937評論 2 361

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