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

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

JVM 在執(zhí)行 Java 程序的過程中會(huì)把它所管理的內(nèi)存劃分為若干個(gè)不同的數(shù)據(jù)區(qū)域。這些區(qū)域有各自的用途疆偿,以及創(chuàng)建和銷毀的時(shí)間,有的區(qū)域隨著虛擬機(jī)進(jìn)程的啟動(dòng)而一直存在猾瘸,有些區(qū)域則是依賴用戶線程的啟動(dòng)和結(jié)束而建立和銷毀勉盅。

JVM 所管理的內(nèi)存會(huì)包括以下幾個(gè)運(yùn)行時(shí)數(shù)據(jù)區(qū)域:

image

Java 堆

Java 堆(Java Heap) 是虛擬機(jī)所管理的內(nèi)存中最大的一塊铆农。Java 堆是被所有線程共享的一塊內(nèi)存區(qū)域牺氨,在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建。此區(qū)域的唯一目的就是存放對(duì)象實(shí)例墩剖,幾乎所有的對(duì)象實(shí)例都在這里分配內(nèi)存波闹。

為什么是幾乎呢?從實(shí)現(xiàn)角度來看涛碑,隨著 Java 語言的發(fā)展精堕,現(xiàn)在已經(jīng)能看到一些跡象表明日后可能出現(xiàn)值類型的支持,即使只考慮現(xiàn)在蒲障,由于JIT編譯器的發(fā)展和”逃逸分析”技術(shù)的逐漸成熟歹篓,棧上分配、標(biāo)量替換等優(yōu)化技術(shù)使得對(duì)象一定分配在堆上這件事情已經(jīng)變得不那么絕對(duì)了揉阎。

方法區(qū)

方法區(qū)(Method Area)與 Java 堆一樣庄撮,是各個(gè)線程共享的內(nèi)存區(qū)域,它用于存儲(chǔ)已被虛擬機(jī)加載的類型信息毙籽、常量洞斯、靜態(tài)變量、即時(shí)編譯器編譯后的代碼緩存等數(shù)據(jù)坑赡。

程序計(jì)數(shù)器

程序計(jì)數(shù)器(Program Counter Register)是一塊較小的內(nèi)存空間烙如,它可以看作是當(dāng)前線程索所執(zhí)行的字節(jié)碼的行號(hào)指示器。

Java 虛擬機(jī)棧

Java 虛擬機(jī)棧(JVM Stacks)毅否,與程序計(jì)數(shù)器一樣也是線程私有的亚铁,它的生命周期與線程相同。虛擬機(jī)棧描述的是 Java 方法執(zhí)行的線程內(nèi)存模型:每個(gè)方法被執(zhí)行的時(shí)候螟加,Java 虛擬機(jī)都會(huì)同步創(chuàng)建一個(gè)棧幀(Stack Frame)用于存儲(chǔ)局部變量表徘溢、操作數(shù)棧、方法出口燈信息捆探。每一個(gè)方法被調(diào)用直至執(zhí)行完畢的過程然爆,就對(duì)應(yīng)著一個(gè)棧幀在虛擬機(jī)棧中從入棧到出棧的過程。

本地方法棧

本地方法棧(Native Method Stacks)與虛擬機(jī)棧所發(fā)揮的作用是非常相似的黍图,其區(qū)別只是虛擬機(jī)棧為虛擬機(jī)執(zhí)行 Java 方法(也就是字節(jié)碼)服務(wù)曾雕,而本地方法棧則是為虛擬機(jī)使用到的本地(Native)方法服務(wù)。

內(nèi)存中的棧(stacks)雌隅、堆(heap)和方法區(qū)(method area)的用法

通常我們定義一個(gè)基本數(shù)據(jù)類型的變量翻默,一個(gè)對(duì)象的引用,還有就是函數(shù)調(diào)用的現(xiàn)場(chǎng)保存都使用JVM中的椙∑穑空間修械。

數(shù)據(jù)類型包括 boolean、byte检盼、char肯污、short、int吨枉、float蹦渣、double。

引用對(duì)象是 reference 類型貌亭,它并不等同于對(duì)象本身柬唯,可能是一個(gè)指向?qū)ο笃鹗嫉刂返闹羔槪部赡苁侵赶蛞粋€(gè)代表對(duì)象的句柄或者其他與此對(duì)象相關(guān)的位置

現(xiàn)場(chǎng)保護(hù)現(xiàn)場(chǎng)恢復(fù)源于匯編中主程序和子程序之間的調(diào)用和返回圃庭,和CPU中斷機(jī)制有關(guān)锄奢。
主程序和子程序通常是分別編制的,所以它們所使用的寄存器往往會(huì)發(fā)生沖突剧腻。如果主程序在調(diào)用子程序之前的某個(gè)寄存器內(nèi)容在從子程序返回后還有用拘央,而子程序又恰好使用了同一個(gè)寄存器,這就破壞了該寄存器的原有內(nèi)容书在,因而造成程序運(yùn)行錯(cuò)誤灰伟,這是不允許的。為避免這種錯(cuò)誤的發(fā)生儒旬,在一進(jìn)入子程序后栏账,就應(yīng)該把子程序所需要使用的寄存器內(nèi)容保存在堆棧中,此過程稱作現(xiàn)場(chǎng)保護(hù)栈源。在退出子程序前把寄存器內(nèi)容恢復(fù)原狀发笔,此過程稱作現(xiàn)場(chǎng)恢復(fù)。現(xiàn)場(chǎng)保護(hù)與現(xiàn)場(chǎng)恢復(fù)分別使用壓棧和彈出指令實(shí)現(xiàn)凉翻。

而通過new關(guān)鍵字和構(gòu)造器創(chuàng)建的對(duì)象則放在堆空間了讨,堆是垃圾收集器管理的主要區(qū)域。

由于現(xiàn)在的垃圾收集器都采用分代收集算法制轰,所以堆空間還可以細(xì)分為新生代和老年代前计,再具體一點(diǎn)可以分為 Eden、Survivor(又可分為From Survivor和To Survivor)垃杖、Tenured男杈。

方法區(qū)和堆都是各個(gè)線程共享的內(nèi)存區(qū)域,用于存儲(chǔ)已經(jīng)被JVM加載的類信息调俘、常量伶棒、靜態(tài)變量旺垒、JIT編譯器編譯后的代碼緩存等數(shù)據(jù)。

運(yùn)行時(shí)常量池(Runtime Constant Pool)是方法區(qū)的一部分肤无,Class 文件中除了有類的版本先蒋、字段、方法宛渐、接口等描述信息外竞漾,還有常量池表(Constant Pool Table),用于存放編譯期生成的各種字面量與符號(hào)引用窥翩,這些內(nèi)容會(huì)在類加載后存放到方法區(qū)的運(yùn)行時(shí)常量池中业岁。

棧空間操作起來最快但是棧很小寇蚊,通常大量的對(duì)象都是放在堆空間笔时,棧和堆的大小都可以通過 JVM 的啟動(dòng)參數(shù)來進(jìn)行調(diào)整,椪贪叮空間用光了會(huì)引發(fā) StackOverflowError 異常糊闽,而堆和常量池空間不足則會(huì)引發(fā) OutOfMemoryError 異常。

舉個(gè)例子:
String str = new String("hello");

上面的語句中變量 str 放在棧上爹梁,用 new 創(chuàng)建出來的字符串對(duì)象放在堆上右犹,而“hello”這個(gè)字面量是放在方法區(qū)的。

補(bǔ)充

運(yùn)行時(shí)常量池相當(dāng)于 Class 文件常量池具有動(dòng)態(tài)性姚垃,Java 語言并不要求常量一定只有編譯期間才能產(chǎn)生念链,運(yùn)行期間也可以將新的常量放入池中,String 類的 intern() 方法就是這樣的积糯。

查看以下代碼執(zhí)行結(jié)果在java7之前和之后的版本中運(yùn)行結(jié)果是否一致:


String s1 = new StringBuilder("go")
    .append("od").toString();
System.out.println(s1.intern() == s1);
String s2 = new StringBuilder("ja")
    .append("va").toString();
System.out.println(s2.intern() == s2);

運(yùn)行結(jié)果:
java7 之前:false,false.
java7 之后:true false
原因:對(duì)于"s1.intern() == s1"掂墓,java7之前,由于運(yùn)行時(shí)常量池存放在方法區(qū)內(nèi)看成,變量s1通過new關(guān)鍵字創(chuàng)建的對(duì)象君编,所以s1是堆空間的引用;而s1.intern()返回的是方法區(qū)中的運(yùn)行時(shí)常量池的引用川慌,因此結(jié)果是false吃嘿;java7之后運(yùn)行時(shí)常量池存放在堆中,因此"s1=new StringBuilder("go").append("od").toString()"會(huì)將"good"直接放到運(yùn)行時(shí)常量池梦重,同時(shí)返回該引用給到s1兑燥;而調(diào)用"s1.intern()"返回的同樣是運(yùn)行時(shí)常量池中該對(duì)象的引用,所以是true琴拧。

對(duì)于"s2.intern() == s2"降瞳,是因?yàn)樵诰幾g后java常量池中已經(jīng)"java"對(duì)象,所以"s2.intern()"返回的始終都是方法區(qū)常量池的對(duì)象引用蚓胸,所以結(jié)果都是false挣饥。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末除师,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子扔枫,更是在濱河造成了極大的恐慌汛聚,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件茧吊,死亡現(xiàn)場(chǎng)離奇詭異贞岭,居然都是意外死亡八毯,警方通過查閱死者的電腦和手機(jī)搓侄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來话速,“玉大人讶踪,你說我怎么就攤上這事〔唇唬” “怎么了乳讥?”我有些...
    開封第一講書人閱讀 158,369評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)廓俭。 經(jīng)常有香客問我云石,道長(zhǎng),這世上最難降的妖魔是什么研乒? 我笑而不...
    開封第一講書人閱讀 56,799評(píng)論 1 285
  • 正文 為了忘掉前任汹忠,我火速辦了婚禮,結(jié)果婚禮上雹熬,老公的妹妹穿的比我還像新娘宽菜。我一直安慰自己,他們只是感情好竿报,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,910評(píng)論 6 386
  • 文/花漫 我一把揭開白布铅乡。 她就那樣靜靜地躺著,像睡著了一般烈菌。 火紅的嫁衣襯著肌膚如雪阵幸。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,096評(píng)論 1 291
  • 那天芽世,我揣著相機(jī)與錄音侨嘀,去河邊找鬼。 笑死捂襟,一個(gè)胖子當(dāng)著我的面吹牛咬腕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播葬荷,決...
    沈念sama閱讀 39,159評(píng)論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼涨共,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼纽帖!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起举反,我...
    開封第一講書人閱讀 37,917評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤懊直,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后火鼻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體室囊,經(jīng)...
    沈念sama閱讀 44,360評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,673評(píng)論 2 327
  • 正文 我和宋清朗相戀三年魁索,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了融撞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,814評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡粗蔚,死狀恐怖尝偎,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鹏控,我是刑警寧澤致扯,帶...
    沈念sama閱讀 34,509評(píng)論 4 334
  • 正文 年R本政府宣布,位于F島的核電站当辐,受9級(jí)特大地震影響抖僵,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜缘揪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,156評(píng)論 3 317
  • 文/蒙蒙 一耍群、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧寺晌,春花似錦世吨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至陆赋,卻和暖如春沐祷,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背攒岛。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評(píng)論 1 267
  • 我被黑心中介騙來泰國(guó)打工赖临, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人灾锯。 一個(gè)月前我還...
    沈念sama閱讀 46,641評(píng)論 2 362
  • 正文 我出身青樓兢榨,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子吵聪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,728評(píng)論 2 351

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