一文看懂 JVM 內(nèi)存區(qū)域分布與作用
作者:bingfeng
來源:SegmentFault 思否社區(qū)
那么我們在開始介紹Java內(nèi)存區(qū)域之前,我們先放一張內(nèi)存區(qū)域的圖,方便我們后面介紹的時候可以對照著看。
須知,本文是根據(jù)JDK8來介紹的。

程序計數(shù)器
首先它是線程私有的,它也稱為代碼的行號指示器,字節(jié)碼解釋器就是通過改變程序計數(shù)器的位置來確定下一行要執(zhí)行的代碼,它不存在OOM。
如果線程正在執(zhí)行一個Java方法,那么它記錄的是正在執(zhí)行虛擬機字節(jié)碼指令的地址,如果是一個本地方法那么它的值為空。
Java 虛擬機棧
它也是線程私有的,它的聲明周期和線程一致。每個線程創(chuàng)建時都會創(chuàng)建一個虛擬機棧,內(nèi)部保存了一個個的棧幀,每個棧幀就對應著一次方法的調(diào)用。既然知道了虛擬機棧里面存放的是一個個的棧幀,那么也不難猜出虛擬機棧里面都存儲了什么東西。
Java虛擬機棧是存在OOM的,當線程所請求的棧的深度大于虛擬機棧的深度或者虛擬機??梢詣討B(tài)擴容,當棧擴展時無法申請到足夠的內(nèi)存時,就會拋出OOM。
虛擬機棧內(nèi)部結構:

局部變量表:
主要存儲方法的參數(shù),所有的基本類型數(shù)據(jù)和對象地址,以及返回地址類型(return address)。它以變量槽為最小的存儲單位,Java虛擬機并沒有規(guī)定一個變量槽占用多少內(nèi)存空間,但是規(guī)定了一個變量槽可以存放一個32位以內(nèi)的數(shù)據(jù)類型。如果存儲的數(shù)據(jù)類型超過32位,比如long、double,那么就使用兩個變量槽進行存儲。
操作數(shù)棧:
操作數(shù)棧是一個先進后出的操作數(shù)棧,當一個方法剛開始執(zhí)行的時候,一個新的棧幀也會隨之被創(chuàng)建出來,這個方法的操作數(shù)棧是空的,它主要用于保存計算過程的中間結果,同時作為計算過程中變量臨時的存儲空間。如果被調(diào)用的方法有返回值,那么返回值將會被壓入當前棧幀的操作數(shù)棧中。操作數(shù)棧并非采用索引的方式進行數(shù)據(jù)訪問,而是通過入棧(push)和出棧(pop)操作來完成數(shù)據(jù)的訪問。
動態(tài)鏈接:
大白話就是,棧幀中保存了一個方法的引用,當執(zhí)行方法的時候,可以拿著這個引用到運行時常量池中找到這個方法。
動態(tài)鏈接的作用就是將這些方法的符號引用轉換為調(diào)用方法的直接引用。
方法返回地址:
就是在方法執(zhí)行結束之后,要返回下一條要執(zhí)行代碼位置的值,也就是程序計數(shù)器的值。
那么除了方法正常執(zhí)行結束退出外,還有另外一種情況就是異常導致的方法退出,那么這種情況下是不會返回任何值的。對于拋出的異常,棧幀中不會做任何記錄,但是會記錄在一個異常表中。
本地方法棧
Java堆
方法區(qū)
運行時常量池

