Java虛擬機 —— 運行時數據區

Java虛擬機內存,是指JVM的運行時數據區域,主要分為:方法區、堆、虛擬機棧、本地方法棧、程序計數器。其中方法區和堆為索引線程的共享數據區,而虛擬機棧、本地方法棧、程序計數器為線程隔離的數據區。


程序計數器

每個線程都有一個獨立的計數器用來記錄程序當前執行的指令,可以看成是當前線程所執行的字節碼的行號指示器。如果線程正在執行Java方法,計數器記錄的是正在執行的虛擬機字節碼指令的地址;如果執行的是Native方法,計數器記錄值為空(Undefined)。程序計數器占用的內存空間非常小,是線程的私有區域,此內存區域是唯一一個在Java虛擬機規范中沒有規定任何OutOfMemoryError情況的區域。

虛擬機棧

虛擬機棧也是線程私有的,它的生命周期與線程相同。虛擬機棧是一個后進先出的數據結構,里面存放的是棧幀,每個Java方法的調用對應一個棧幀在虛擬機棧中的入棧和出棧。當線程執行一個Java方法執行時,就會創建一個新的棧幀并壓入到該線程的虛擬機棧的棧頂,Java方法執行結束后棧頂的該棧幀就會彈出棧并銷毀。

棧幀里面存放的是Java方法執行的一些數據,包括局部變量表、操作數棧、動態連接、方法出口等。


局部變量表

局部變量表是一組變量值存儲空間,用于存放方法參數和方法內部定義的局部變量。

局部變量表的容量以變量槽(Slot)為最小單位,32位虛擬機中一個Slot可以存放一個32位以內的數據類型(boolean、byte、char、short、int、float、reference和returnAddress八種)。reference類型虛擬機規范沒有明確說明它的長度,但一般來說,虛擬機實現至少都應當能從此引用中直接或者間接地查找到對象在Java堆中的起始地址索引和方法區中的對象類型數據。returnAddress類型是為字節碼指令jsr、jsr_w和ret服務的,它指向了一條字節碼指令的地址。

Java虛擬機是使用局部變量表完成參數值到Java方法參數變量列表的傳遞過程的,如果是實例方法(非static),那么局部變量表的第0位索引的Slot默認是用于傳遞方法所屬對象實例的引用,在方法中通過this訪問。

Slot是可以重用的,下一次分配Slot的時候,將會覆蓋原來的數據。Slot對對象的引用會影響GC(要是被引用,將不會被回收)。

操作數棧

操作數棧也常被稱為操作棧,同樣是一個后進先出的數據結構。當一個方法剛剛開始執行的時候,這個方法的操作數棧是空的,在方法的執行過程中,會有各種字節碼指令向操作數棧中寫入和提取內容,也就是入棧出棧操作。在做算術運算的時候是通過操作數棧來進行的,在調用其他方法的時候是通過操作數棧來進行參數傳遞的。JVM將操作數棧作為工作區。JVM沒有寄存器,所有的參數傳遞和返回值都是基于操作數棧來完成的。

比如,執行引擎執行c = a + b時,會先被操作的參數ab壓入操作數棧,然后操作指令將他們彈出棧,并執行操作,將結果再壓入棧。

Java虛擬機的解釋執行引擎稱為“基于棧的執行引擎”,其中所指的“棧”就是操作數棧。

動態連接

每個棧幀都包含一個指向運行時常量池中該棧幀所屬方法的引用,持有這個引用是為了支持方法調用過程中的動態連接。Class文件的常量池有存有大量的符號引用,字節碼中的方法調用指令就以常量池中指向方法的符號引用為參數。這些符號引用一部分會在類加載階段或第一次使用的時候轉化為直接引用,這種轉化稱為靜態解析。另外一部分將在每一次的運行期間轉化為直接引用,這部分稱為動態連接。

方法出口(返回地址)

當一個方法被執行后,有兩種方式退出這個方法。第一種方式是執行引擎遇到任意一個方法返回的字節碼指令,這時候可能會有返回值傳遞給上層的方法調用者(調用當前方法的方法稱為調用者),是否有返回值和返回值的類型將根據遇到何種方法返回指令來決定,這種退出方法的方式稱為正常完成出口(Normal Method Invocation Completion)。

另外一種退出方式是,在方法執行過程中遇到了異常,并且這個異常沒有在方法體內得到處理,無論是Java虛擬機內部產生的異常,還是代碼中使用athrow字節碼指令產生的異常,只要在本方法的異常表中沒有搜索到匹配的異常處理器,就會導致方法退出,這種退出方法的方式稱為異常完成出口(Abrupt Method Invocation Completion)。一個方法使用異常完成出口的方式退出,是不會給它的上層調用者產生任何返回值的。

無論采用何種退出方式,在方法退出之后,都需要返回到方法被調用的位置,程序才能繼續執行,方法返回時可能需要在棧幀中保存一些信息,用來幫助恢復它的上層方法的執行狀態。一般來說,方法正常退出時,調用者的PC計數器的值就可以作為返回地址,棧幀中很可能會保存這個計數器值。而方法異常退出時,返回地址是要通過異常處理器來確定的,棧幀中一般不會保存這部分信息。

方法退出的過程實際上等同于把當前棧幀出棧,因此退出時可能執行的操作有:恢復上層方法的局部變量表和操作數棧,把返回值(如果有的話)壓入調用者棧幀的操作數棧中,調整PC計數器的值以指向方法調用指令后面的一條指令等。

虛擬機棧Error

Java虛擬機棧有可能出現的error就是StackOverflowErrorOutOfMemoryError。當線程請求的棧深度大于Java虛擬機棧允許的深度時,就會拋出StackOverflowError錯誤。比如將一個方法反復遞歸,最終就會出現StackOverflowError。當Java虛擬機棧可以動態擴展時(大部分的 Java 虛擬機都可動態擴展,不過 Java 虛擬機規范中也允許固定長度的虛擬機棧),如果無法申請到足夠的內存來擴展棧,就會拋出OutOfMemoryError錯誤。

本地方法棧

本地方法棧與虛擬機棧的功能類似,他們的區別在于虛擬機棧為執行Java代碼方法服務,而本地方法棧是為Native方法服務。本地方法棧就是一個C的方法棧,本地方法棧的參數順序、返回值和典型的C程序相同,本地方法一般來說可以(依賴 JVM 的實現)反過來調用 JVM 中的 Java 方法。這種native方法調用Java會發生在棧(一般是Java棧)上,線程將離開本地方法棧,并在 Java 棧上開辟一個新的棧幀。

與虛擬機棧一樣,本地方法棧也會拋出StackOverflowErrorOutOfMemoryError

堆是Java虛擬機中最大的一塊內存區域,它是有所有的線程共享。幾乎所有的實例對象和數組都是在堆中存放。只要是通過new關鍵字創建對象或者直接聲明數組,都會在堆中開辟內存空間來存放。因為在棧幀被創建后無法調整大小,棧幀中只能存放對象和數組在堆中的引用。方法或線程結束時對象和數組不會立即被移除銷毀,它只能由垃圾回收器回收。

同樣地,如果在堆中沒有內存來完成實例分配,并且堆也無法擴展時,將會拋出OutOfMemoryError

方法區

方法區與堆一樣,是各個線程共享的內存區域,它存儲已經被虛擬機加載的類信息(包括字段信息、方法信息、方法代碼等)、常量、靜態變量、即時編譯器編譯后的代碼等數據。

方法區中的內存一般不會被GC回收,GC也很難回收。方法區的內存回收主要是針對針對常量池的回收和對類的卸載。根據 Java 虛擬機規范的規定,當方法區無法滿足內存分配需求時,將拋出OutOfMemoryError異常。

運行時常量池

運行時常量池是方法區的一部分,Class文件除了有關類的版本、字段、方法、接口等描述信息外,還有一項信息是常量池,用于存放編譯期生成的各種字面量和符號引用,這部分內容將在類加載后進入方法區的運行時常量池中存放。運行時常量池可以理解為是類或接口的常量池的運行時表現形式。


參考:

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,663評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,125評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,506評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,614評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,402評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,934評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,021評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,168評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,690評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,596評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,288評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,027評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,404評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,662評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,398評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,743評論 2 370

推薦閱讀更多精彩內容