JVM 运行时数据区域总结
引言
本博客總結自《深入理解 Java 虛擬機》,第二章。
一、概述
Java 虛擬機在執行 Java 程序的時候會把它所管理的內存劃分為若干個不同的數據區域。
記憶口訣:兩棧一計數,一堆一方法。
解釋:第一句兩棧分別是VM棧和本地方法棧,一計數指的是程序計數器,它們都是線程私有;后一句,一堆指的是Java堆,一方法指的是方法區,這兩個區域是線程共享。
二、程序計數器
程序計數器是一個較小的內存空間,它可以看做是當前線程所執行的字節碼的行號指示器。
在虛擬機的概念模型(實現各有不同)中字節碼解釋器工作時就是通過改變程序計數器的值來選取下一條需要執行的字節碼指令,這與程序的分支、循環、跳轉、異常處理、線程恢復等基礎功能緊密相關。
在這里,書中提到:
Java 虛擬機的多線程是通過線程輪流切換并分配一個 CPU 內核執行時間的方式來實現的,任何一個時間點,一個CPU 內核都只會執行一條線程中的指令。
正因為這樣的線程實現策略,要想在線程切換后恢復到正確的執行位置,這個程序計數器必須是線程私有,獨立存儲。
程序計數器可以存儲兩種內容,字節碼指令地址或空值。
當線程正在執行的是 Java 方法的時候,存儲字節碼指令地址,而當執行的是Native 方法的時候,則為空值。
另外,值得注意的是,此內存區域是 JVM 規范中唯一沒有規定任何 OOM Error情況的區域。也就是說,如果你的程序突然報了 OutOfMemory Error 錯誤,那么肯定不是這個區域出了問題。
三、JVM 棧
JVM 棧又稱為 Java 虛擬機棧,或 VM 棧。
這塊邏輯分區存儲的方法調用信息。Java 方法在調用的時候,會在 JVM 棧中創建一個 棧幀(Stack Frame),它會用于存儲方法內部所用到的局部變量表、操作數棧、動態鏈接、方法返回地址等信息。其中最需要程序開發人員關心的是存儲局部變量的局部變量表。
方法開始執行,棧幀入棧,方法執行完畢,棧幀出棧,以此來實現線程中方法的調用。
因此,從上面的特征來看, JVM 棧也一定是線程私有的。生命周期與線程相同。
局部變量表,存儲編譯期可知的基本數據類型變量(double、long 占 2 個 Slot 局部變量空間,其他 1 個)、對象引用、以及 returnType。
局部變量表的內存分配是在編譯期間完成分配。當進入一個方法時,這個方法需要在棧幀中分配多大的局部變量空間是完全確定的,在方法運行期間不會改變局部變量表的大小。
一般情況下 JVM 棧不會輕易拋出異常,但是有一種情況經常會導致 StackOverflowError 異常,就是遞歸。
遞歸是一種通過調用方法自身向“基準情況”不斷推進的一種算法,但是基準情況的判斷無法在編譯期給出答案,這就導致了,如果無法在有限的棧深度給出問題的解,方法就會不停地調用自身,從而將 JVM 棧空間占滿,那么就會導致?StackOverflowError 異常。但現代的大多數虛擬機都支持動態擴展這塊內存區域,但如果連動態申請的內存依然無法滿足計算需要,就會報 OutOfMemoryError 異常。
?
總結
以上是生活随笔為你收集整理的JVM 运行时数据区域总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Git初学札记(六)————在远程新建本
- 下一篇: ssm项目集成ftp_ssm开发旅游信息