天天看點

深入了解Java虛拟機(一)——虛拟機的記憶體結構

JVM-JVM記憶體結構

參考資料:

連結:Java虛拟機的記憶體組成以及堆記憶體介紹-HollisChuang's

Blog連結:Java堆和棧看這篇就夠 - Johnny-Zhuang's Technology

Java 記憶體之方法區和運作時常量池 - 漠然的部落格 | mritd Blog

連結:從0到1起步-跟我進入堆外記憶體的奇妙世界 - 簡書

一、虛拟機棧

棧主要用來存儲局部變量和方法的調用。棧中的記憶體是線程私有的并且生命周期跟線程相同。棧主要是由棧幀組成。當線程調用java的方法時候,會形成一個棧幀并壓入到棧中。當棧空間不足時,會抛出StackOverFlowError異常。
棧幀主要是由局部變量表、操作數棧和幀資料區這三部分組成的。

        (1)局部變量表

                    局部變量表是由數組構成是以通過索引即可進行通路,它主要存放的是基本資料類型(short,byte,int,char,boolean,double,long)和reference類型(對象的引用),當存入一個long或者double類型的時候會在數組中形成連續的兩項,要取值的時候隻需取其第一個索引即可。

        (2)操作數棧

                    操作數棧主要是用來存儲臨時的操作資料,例如:當兩個局部變量進行計算時,會先将變量入棧到操作數棧中,進行計算完成後會将結果先放在操作數棧中,是以操作數棧主要用來存放臨時的資料。

        (3)幀資料區

                   幀資料區主要是通過資料用來支援常量池的解析和方法的正常傳回以及異常的處理。當需要用到常量池時,JVM會使用幀資料區中指向常量池的指針。當方法正常傳回時,幀裡的資料會處理,使之從棧中彈出,恢複到發起調用的方法棧中,如果有傳回值時,會将傳回值儲存到發起調用該方法的操作數棧當中。當方法抛出異常時,JVM執行catch塊中的代碼,如果沒有,則直接終止,然後JVM用幀資料區中的資料資訊恢複到發起調用該方法的棧幀中,然後向上抛出同樣的異常。

二、本地方法棧

與虛拟機棧類似,主要為Native方法服務。

三、方法區

           是全局共享的一塊記憶體區域,主要存儲的是定義在類中的常量、靜态變量、類中聲明的方法和方法字段等。預設最小值為16MB,最大值為64MB,可用-XX:PermSize和-XX:MaxPermSize參數限制方法區的大小。

            運作常量池是方法區中的一部分。同樣是全局共享的區域。運作常量池主要存放的是Class被編譯器編譯生成的各種符号引用。當運作時常量池無法申請到新的記憶體時,會抛出OutOfMemoryError異常。

四、堆

        堆是全局共享的區域,主要存放的是對象的執行個體以及數組(所有new的對象)。可通過-Xms(最小值),-Xmx(最大值)等參數來設定堆的大小,預設當空餘堆記憶體大于70%時,JVM會減小堆記憶體到-Xms指定大小的值,預設當空餘堆小于40%是,JVM會增加堆記憶體到-Xmx指定的大小值,為了避免運作時頻繁的調整堆的大小,通常将-Xms和-Xmx設定成一樣。現在收集器采用的是分代收集器,是以堆記憶體劃分為新生代、老年代和持久代。新生代主要存儲新建立的對象和尚未進入老年代的對象,老年代存儲的是經過多次新生代GC依然存活的對象(例如:緩存對象)。新生代主要由Eden Space和兩塊一樣大小的 From Space和To Space構成。

五、程式計數器

        它是目前線程所執行位元組碼的行号訓示器。位元組碼解釋器通過改變程式計數器來選取下一條需要執行的位元組碼指令,分支、循環、異常處理、線程恢複等基礎功能。