JVM(七):JVM內存結構

JVM(七):JVM內存結構

在前幾節(jié)的文章我們多次講到 Class 對象需要分配入 JVM 內存越平,并在 JVM 內存中執(zhí)行 Java 代碼频蛔,完成對象內存的分配、執(zhí)行秦叛、回收等操作晦溪,因此,如今讓我們來走入 JVM挣跋,看看 JVM 中的內存結構是如何構造的三圆,下面就讓我們一探究竟吧。

內存劃分

在本小節(jié)中避咆,我們以《Java 虛擬機規(guī)范》中的要求舟肉,并以當前主流虛擬機 Hotspot VM 為例,詳細講述內存區(qū)域中各個模塊的劃分查库,了解其各自的用途以及其為何如何劃分等路媚。

首先讓我們來看一下 Java 虛擬機內存的劃分方式。

JVM內存區(qū)域

JVM 將內存劃分為 5個部分樊销,分別為線程共享的 方法區(qū)整慎,以及線程私有的 程序計數器虛擬機棧本地方法棧围苫,下面就讓我們針對這 5個區(qū)域進行學習院领,探究其存儲數據,生命周期和功能够吩。

程序計數器

是一塊較小的內存區(qū)域比然,可以看做是當前線程執(zhí)行的字節(jié)碼的行號指示器。在虛擬機概念模型里周循,字節(jié)碼解析器就是通過改變這個計數器的值來選取下一條需要執(zhí)行的字節(jié)碼强法,因此其在分支,循環(huán)湾笛,跳轉饮怯,異常跳轉,線程恢復等功能上都有著大作用嚎研。

PS:如果執(zhí)行的是本地方法蓖墅,那么這個計數器的值則為空。

虛擬機棧

虛擬機棧也是線程私有的临扮,其內描述的是 Java 方法執(zhí)行的內存模型论矾,即在每個執(zhí)行同時創(chuàng)建一個棧幀,棧幀內存儲局部變量表杆勇,操作數棧贪壳,動態(tài)鏈接,方法出口等信息蚜退。每一個方法從開始到結束就對應著一個棧幀從入棧到出棧的過程闰靴。同時只有位于棧頂的棧幀才是有效的彪笼,與其關聯的方法稱為當前方法,執(zhí)行引擎的所有字節(jié)碼指令都只針對當前棧幀進行操作蚂且。

虛擬機棧

局部變量表

用于存放方法參數和方法內部定義的局部變量配猫,其在 Java 程序被編譯為 Class 文件后,就已經確定了所需的最大容量杏死。

其容量以變量槽(slot)為最小單位章姓。因此在使用過程中是通過索引定位來使用局部變量表的,索引范圍為 0~~slot 最大值识埋。其中如果執(zhí)行的是非 static 方法,那么0則默認為 方法所屬對象實例引用零渐,對應 Java 關鍵字的 this窒舟。其余參數按照順序對應 1之后的槽位。

操作數棧

操作棧是一個后入先出的棧诵盼,其最大深度在編譯時也已經確定惠豺。其對應著方法執(zhí)行過程中,各種字節(jié)碼指令往操作數棧寫入和提取內容风宁,也就是所謂的 入棧/出棧 操作洁墙。

也正是操作數棧的存在,因此Java執(zhí)行引擎也被稱為 基于棧的執(zhí)行引擎戒财,與基于 基于寄存器的執(zhí)行引擎 形成對比热监。

Java采取「基于棧的執(zhí)行引擎」考慮到兩點:

  1. Java是一門跨平臺的語言,而不同機器的寄存器實現是不同的饮寞,有多又少孝扛,不利于統一;
  2. 為了使 class 文件更加的緊湊幽崩,這樣設計可以使得大多數指令對齊苦始,并且操作碼只占一個字節(jié)大小,減少數據量慌申。

動態(tài)連接

指向運行時常量池中該棧幀所屬方法的引用陌选,通過這個引用可以完成動態(tài)調用。

關于方法調用過程中的引用詳細解析過程蹄溉,在日后的「方法調用」中咨油,再具體描述。

返回地址

一個方法在執(zhí)行完成后都需要返回到方法被調用的位置柒爵,讓程序繼續(xù)執(zhí)行臼勉。

在方法正常執(zhí)行完成退出后,調用者的程序計數器的值就可以作為返回地址存在棧幀中餐弱,而在方法異常退出后宴霸,返回地址則是通過異常處理器表來確定了囱晴。

附加信息

附加信息不是虛擬機規(guī)范中必須要求有的,但其允許實現者可以增加一些特殊信息到棧幀中瓢谢,例如與調試相關的信息畸写,這部分信息取決于具體的虛擬機實現,在這里不再贅述氓扛。

本地方法棧

本地方法棧和虛擬機棧的作用類似枯芬,區(qū)別僅僅是虛擬機棧為虛擬機執(zhí)行的 Java 方法服務,而本地方法棧則是為 Native 方法服務采郎。其具體實現由虛擬機自行規(guī)定千所。

Java 堆是線程共享的。在一般情況下蒜埋,堆可以說是 Java 內存中最大的內存區(qū)域淫痰。其存放了對象實例,幾乎所有的對象實例在這里存儲整份。(這里說是幾乎待错,是因為 JIT優(yōu)化的存在,可能會有對象不在堆上分配烈评,而在棧上進行分配)火俄。

由于目前考慮到垃圾回收算法大部分都是分代算法,因此堆又可以細分為以下幾塊:

堆內存

但從其內存本質來看讲冠,其并沒有詳細的區(qū)別瓜客,都是用來存儲對象實例的,這種劃分方式是從內存回收的角度來闡述的竿开,因此具體存放邏輯放在「內存回收」中再詳細闡述忆家。

方法區(qū)

方法區(qū)也是線程共享的。其中存放的是被虛擬機加載的類信息德迹,常量芽卿,靜態(tài)變量,即時編譯器編譯后的代碼等數據胳搞。在HotSpot JDK7 以前的具體實現中卸例,這部分被稱為永久代,和堆一起 JVM 管理肌毅。但在JDK8之后筷转,這部分已經用 元數據(meta space) 來替代了。此外像字符串常量池也被從這一模塊移除悬而,轉而用堆來實現呜舒。

常量池

JDK7 之后將以前放在方法區(qū)的常量池放在堆中進行實現,例如 String 的 intern() 方法笨奠,在 JDK8 之后改為如果存在堆中的引用袭蝗,則直接返回堆中引用唤殴,而并不會重新創(chuàng)建對象。

下面讓我們來看一下這段代碼在 JDK8 下的結果是什么到腥。

    String s = new String("1");
    s.intern();
    String s2 = "1";
    System.out.println(s == s2);

    String s3 = new String("1") + new String("1");
    s3.intern();
    String s4 = "11";
    System.out.println(s3 == s4);

該代碼在JDK8下輸出結果為:

false
true

下面就讓我們用下圖來分析一下是為什么:

intern()

String s = new String("1") 這句生成了兩個對象朵逝,一個是對象 obj(1),另一個在 String pool 中乡范,是 "1"配名,s 則是指向對象。s.intern() 因為 "1" 在String pool中已經存在晋辆,所以直接返回渠脉,String s2 = "1",則是直接返回String pool中的引用給s2瓶佳,最后比較的是兩個指向不同地方的引用芋膘,因此結果不同。

String s3 = new String("1") + new String("1") 生成了兩個對象涩哟,一個是對象obj(11),一個是String pool 中的 "1"盼玄,s3.intern() 判斷當 堆中存在對象的時候贴彼,則在字符串常量池中保存該對象的引用,然后返回該對象的引用值埃儿,String s4 = "11" 則讓 s4 指向 String pool 中的值器仗,而 該引用的值就是obj(11)的引用,在最后 System.out.println(s3 == s4) 判斷相等的時候童番,兩個引用其實指向的是同一個值精钮,因此返回相等。

直接內存

Direct Memory 不屬于 JVM 所管的內存區(qū)域剃斧,其受到機器總內存的影響轨香。在具體使用中采用一個在 Java 堆中的DirectByteBuffer對象作為這塊內存的引用進行操作。

總結

在本文中我們學習了 JVM 在其內部是如何劃分區(qū)域進行功能協作的幼东。了解了其內部將 JVM 劃分哪幾個模塊臂容,每個模塊各自又都有神馬作用,其中存儲了什么數據根蟹,每個模塊的不同特性等脓杉。

在下文中,我們將講述對象在堆中的存儲简逮,使用方式球散,了解的Java的 對象模型

iceWang公眾號

文章在公眾號「iceWang」第一手更新散庶,有興趣的朋友可以關注公眾號蕉堰,第一時間看到筆者分享的各項知識點凌净,謝謝!筆芯嘁灯!

本系列文章主要借鑒自《深入分析 JavaWeb 技術內幕》和《深入理解 Java 虛擬機-JVM 高級特性與最佳實踐》泻蚊。

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市丑婿,隨后出現的幾起案子性雄,更是在濱河造成了極大的恐慌,老刑警劉巖羹奉,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件秒旋,死亡現場離奇詭異,居然都是意外死亡诀拭,警方通過查閱死者的電腦和手機迁筛,發(fā)現死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來耕挨,“玉大人细卧,你說我怎么就攤上這事⊥舱迹” “怎么了贪庙?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長翰苫。 經常有香客問我止邮,道長,這世上最難降的妖魔是什么奏窑? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任导披,我火速辦了婚禮,結果婚禮上埃唯,老公的妹妹穿的比我還像新娘撩匕。我一直安慰自己,他們只是感情好墨叛,可當我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布滑沧。 她就那樣靜靜地躺著,像睡著了一般巍实。 火紅的嫁衣襯著肌膚如雪滓技。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天棚潦,我揣著相機與錄音令漂,去河邊找鬼。 笑死,一個胖子當著我的面吹牛叠必,可吹牛的內容都是我干的荚孵。 我是一名探鬼主播,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼纬朝,長吁一口氣:“原來是場噩夢啊……” “哼收叶!你這毒婦竟也來了?” 一聲冷哼從身側響起共苛,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤判没,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后隅茎,有當地人在樹林里發(fā)現了一具尸體澄峰,經...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年辟犀,在試婚紗的時候發(fā)現自己被綠了俏竞。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡堂竟,死狀恐怖魂毁,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情出嘹,我是刑警寧澤席楚,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站疚漆,受9級特大地震影響酣胀,放射性物質發(fā)生泄漏刁赦。R本人自食惡果不足惜娶聘,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望甚脉。 院中可真熱鬧丸升,春花似錦、人聲如沸牺氨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽猴凹。三九已至夷狰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間郊霎,已是汗流浹背沼头。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人进倍。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓土至,卻偏偏與公主長得像,于是被迫代替她去往敵國和親猾昆。 傳聞我的和親對象是個殘疾皇子陶因,可洞房花燭夜當晚...
    茶點故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內容

  • 內存溢出和內存泄漏的區(qū)別 內存溢出:out of memory,是指程序在申請內存時垂蜗,沒有足夠的內存空間供其使用楷扬,...
    Aimerwhy閱讀 741評論 0 1
  • 這篇文章是我之前翻閱了不少的書籍以及從網絡上收集的一些資料的整理,因此不免有一些不準確的地方么抗,同時不同JDK版本的...
    高廣超閱讀 15,601評論 3 83
  • 第二部分 自動內存管理機制 第二章 java內存異常與內存溢出異常 運行數據區(qū)域 程序計數器:當前線程所執(zhí)行的字節(jié)...
    小明oh閱讀 1,164評論 0 2
  • 文章轉自 http://blog.csdn.net/u012152619/article/details/4696...
    云狗狗狗狗狗閱讀 606評論 1 4
  • 第一步毅否,了解JVM基本概念,基本結構蝇刀。 第二步螟加,了解JVM中線程私有區(qū)和公有區(qū)。 第三步吞琐,了解線程與Java內存模...
    Arya鑫閱讀 1,194評論 0 10