Java虛擬機(二):Java虛擬機運行時數(shù)據(jù)區(qū)域

JVM對于是每個Java程序員掌握一定Java基礎(chǔ)后棉浸,都需要學(xué)習(xí)的揖曾。因為很多代碼問題贩毕,只能了解了JVM底層原理后才能解決悯许。大多數(shù)Java后端開發(fā)者都知道堆(Heap)和棧(Stack)的概念,卻沒有真正理解其原理辉阶。推薦《深入理解Java虛擬機(第二版)》---周志明著學(xué)習(xí)JVM岸晦。

進程和線程

學(xué)習(xí)JVM前要了解進程和線程的概念。

以下是一個類比睛藻,來自阮一峰---進程與線程的一個簡單解釋

  1. 計算機的CPU是像一座工廠邢隧,時刻在運行店印。
  2. 因工廠電力有限,一次只能供給一個車間使用倒慧。也就是說按摘,一個車間開工的時候,其他車間都必須停工纫谅。背后的含義就是炫贤,單個CPU一次只能運行一個任務(wù)。
  3. 進程就好比工廠的車間付秕,它代表CPU所能處理的單個任務(wù)兰珍。任一時刻,CPU總是運行一個進程询吴,其他進程處于非運行狀態(tài)掠河。
  4. 一個車間里亮元,可以有很多工人。他們協(xié)同完成一個任務(wù)唠摹。
  5. 線程就好比車間里的工人爆捞。一個進程可以包括多個線程。

進程和線程里面還涉及到“鎖”的知識勾拉,請在參考網(wǎng)址中學(xué)習(xí)煮甥。

下圖是:Java虛擬機運行時數(shù)據(jù)區(qū)

程序計數(shù)器(Program Counter Resiger)

首先程序計數(shù)器是一塊較小的內(nèi)存空間,“決定”當(dāng)前線程字節(jié)碼的執(zhí)行順序藕赞,因為它存儲字節(jié)碼的行號成肘。而在多線程中,每個線程都具有一個程序計數(shù)器找默,各條線程之間獨立艇劫,計數(shù)器互不影響,獨立存儲惩激。程序計數(shù)器是“線程私有”的內(nèi)存店煞。

如果線程執(zhí)行Java方法,計數(shù)器記錄的是虛擬機字節(jié)碼指令的地址风钻。而如果執(zhí)行Native方法顷蟀,值為空(Undefined),理解這一段文字需要理解Native方法是什么骡技!Native方法是非Java代碼(比如C)編寫的方法鸣个。程序計數(shù)器是Java虛擬機規(guī)范中唯一沒有OutOfMemoryError的內(nèi)存區(qū)域。

Java虛擬機棧(Java Virtual Machine Stacks)

虛擬機棧是Java方法(也就是字節(jié)碼)運行時的內(nèi)存模型:每個方法在執(zhí)行的同時都會創(chuàng)建一個棧幀(Stack Frame)[幀是一種數(shù)據(jù)結(jié)構(gòu)]用于存儲局部變量表等布朦。它是“線程私有”的囤萤,生命周期和線程相同。

我們常說的棧(Stacks)其中一種含義就是Java虛擬機棧是趴,確切的說是虛擬機棧中局部變量表部分涛舍。局部變量表存放原始(基本)數(shù)據(jù)類型,其中Long和double占兩個局部變量空間(Slot)-32位唆途。也存放對象引用和ruturnAddress類型(指向了一條字節(jié)碼指令的地址富雅?)。

局部變量表所需的內(nèi)存空間在編譯期間完成分配肛搬,當(dāng)進入(運行)一個方法時没佑,這個方法需要在幀中分配多大的局部變量空間是完全確定的,這是因為局部變量表是有結(jié)構(gòu)的温赔,每個區(qū)塊按照一定次序存放蛤奢,所以可以明確知道每個區(qū)塊的大小。局部變量就是在方法運行期間不會改變局部變量表的大小。

Java虛擬機規(guī)范中規(guī)定此區(qū)域有兩種異常:

  • 每次方法調(diào)用都會有一個棧幀壓入虛擬機棧远剩,JVM分配給虛擬機棧的內(nèi)存是有限的扣溺。如果方法調(diào)用過多,導(dǎo)致虛擬機棧滿了就會溢出瓜晤。如果線程請求的棧深度(棧幀的數(shù)量)大于虛擬機所允許的深度(虛擬機棧的內(nèi)存)锥余,將拋出StackOverflowError異常
  • 虛擬機棧可以動態(tài)擴展痢掠,如果擴展時無法申請到足夠的內(nèi)存驱犹,就會拋出OutOfMemoryError異常。

本地方法棧(Native Method Stack)

本地方法棧與Java虛擬機棧類似足画,是虛擬機使用到的Native方法服務(wù)雄驹。Sun HotSpot虛擬機直接本地方法棧和虛擬機棧合二為一。與虛擬機棧一樣淹辞,本地方法棧區(qū)域也會拋出StackOverflowError和OutOfMemoryError異常医舆。

Java堆(Java Heap)

Java堆(Java Heap)是Java虛擬機所管理的內(nèi)存中最大的一塊。是被所有線程共享的一塊內(nèi)存區(qū)域象缀。存放對象實例和數(shù)組(數(shù)組也是對象)蔬将,現(xiàn)在不是那么“絕對”了。

Java堆是垃圾收集器管理的主要區(qū)域央星,因此很多時候也被稱做“GC堆”(Garbage Collected Heap)霞怀。

根據(jù)Java虛擬機規(guī)范,Java堆只要邏輯上是連續(xù)的即可莉给,就像磁盤空間毙石。可以實現(xiàn)成固定大小的颓遏,也可以是可擴展的(大部分虛擬機都可動態(tài)擴展)徐矩。如果堆沒有內(nèi)存完成實例分配,且堆也無法再擴展時叁幢,會拋出OutOfMemoryError異常丧蘸。

方法區(qū)(Method Area)

方法區(qū)(Method Area)不是存儲方法,而是用于存儲已被虛擬機加載的類信息遥皂、常量、靜態(tài)變量刽漂、即時編譯器編譯后的代碼等數(shù)據(jù)演训。Java虛擬機規(guī)范將方法區(qū)描述為堆的一個邏輯部分,是邏輯區(qū)贝咙,但為區(qū)分堆样悟,別名叫Non-Heap(非堆)。

方法區(qū)(Method Area)一樣不需要連續(xù)的內(nèi)存和可以選擇固定大小或者可擴展外,還可以選擇不實現(xiàn)垃圾收集窟她。此區(qū)域的內(nèi)存回收目標(biāo)主要是針對常量池的回收和(對類型的卸載陈症?)。也可能拋出OutOfMemoryError異常震糖。

運行時常量池(Runtime Constant Pool)

運行時常量池(Runtime Constant Pool)是方法區(qū)的一部分录肯。Class文件中除了有類的版本、字段吊说、方法论咏、接口等描述信息外,還有一項信息是常量池(Constant Pool Table)颁井,用于存放編譯期生成的各種字面量(Literal)和符號引用(Symbolic References)厅贪,這部分內(nèi)容將在類加載后進入方法區(qū)的運行時常量池中存放。

字面量比較接近于Java語言層面的常量概念雅宾,如文本字符串养涮、 聲明為final的常量值等。 而符號引用則屬于編譯原理方面的概念眉抬,包括了下面三類常量:

  • 類和接口的全限定名(Fully Qualified Name)
  • 字段的名稱和描述符(Descriptor)
  • 方法的名稱和描述符

對于運行時常量池贯吓,Java虛擬機規(guī)范沒有做任何細(xì)節(jié)的要求。運行時常量池不同于Class文件常量池吐辙,運行期間也可能將新的常量放入池中宣决。內(nèi)存不足時會拋出OutOfMemoryError異常。

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

直接內(nèi)存通俗來說就是I/O方式使用Native堆直接分配堆外內(nèi)存昏苏。

總結(jié)

一般來說尊沸,每個進程分配一個"Heap",每個線程分配一個"Stack"贤惯。因為一個進程中有很多線程洼专,所以Java堆等是線程共享的;而"Stack"的生命周期跟線程相同孵构,即"Stack"是線程獨占的屁商,所以程序計數(shù)器、Java虛擬機棧等是線程私有的颈墅。

image

"Stack"的另外兩種含義有:

  • 一種數(shù)據(jù)結(jié)構(gòu)蜡镶,即一組數(shù)據(jù)的存放方式,特點是FILO---First In,Last Out(先進后出)
  • 一種代碼運行方式恤筛,即"調(diào)用棧"(call Stack)官还,表示函數(shù)或子例程像堆積木一樣存放,以實現(xiàn)層層調(diào)用毒坛。

"Stack"和Heap的主要區(qū)別是:"Stack"是有結(jié)構(gòu)的望伦,"Heap"是沒有結(jié)構(gòu)的林说。因此,"Stack"的尋址速度要快于"Heap"屯伞。

線程共享的好處:任何時候一個線程改變一些數(shù)據(jù)腿箩,其他線程可以看到它。

劣摇?號部分通讀全文理解后解釋珠移。

參考資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市饵撑,隨后出現(xiàn)的幾起案子剑梳,更是在濱河造成了極大的恐慌,老刑警劉巖滑潘,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件垢乙,死亡現(xiàn)場離奇詭異,居然都是意外死亡语卤,警方通過查閱死者的電腦和手機追逮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來粹舵,“玉大人钮孵,你說我怎么就攤上這事⊙勐耍” “怎么了巴席?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長诅需。 經(jīng)常有香客問我漾唉,道長,這世上最難降的妖魔是什么堰塌? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任赵刑,我火速辦了婚禮,結(jié)果婚禮上场刑,老公的妹妹穿的比我還像新娘般此。我一直安慰自己,他們只是感情好牵现,可當(dāng)我...
    茶點故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布铐懊。 她就那樣靜靜地躺著,像睡著了一般瞎疼。 火紅的嫁衣襯著肌膚如雪科乎。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天丑慎,我揣著相機與錄音,去河邊找鬼。 笑死竿裂,一個胖子當(dāng)著我的面吹牛玉吁,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播腻异,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼进副,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了悔常?” 一聲冷哼從身側(cè)響起影斑,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎机打,沒想到半個月后矫户,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡残邀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年皆辽,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片芥挣。...
    茶點故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡驱闷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出空免,到底是詐尸還是另有隱情空另,我是刑警寧澤,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布蹋砚,位于F島的核電站扼菠,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏都弹。R本人自食惡果不足惜娇豫,卻給世界環(huán)境...
    茶點故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望畅厢。 院中可真熱鬧冯痢,春花似錦、人聲如沸框杜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽咪辱。三九已至振劳,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間油狂,已是汗流浹背历恐。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工寸癌, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人弱贼。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓蒸苇,卻偏偏與公主長得像,于是被迫代替她去往敵國和親吮旅。 傳聞我的和親對象是個殘疾皇子溪烤,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,630評論 2 359

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