JVM運行時數據區
Java虛擬機在運行時對該Java進程占用的內存進行的一種邏輯上的划分,包括方法區、堆內存、虛擬機棧、本地方法棧、程序計數器。
這些區塊實際都是Java進程在Java虛擬機的運作下通過不同數據結構來對申請到的內存進行不同使用。
線程共享
堆內存:
存放對象實例及數組
所有線程都可以訪問修改,存放的是對象實例,是數據區中占用空間最大的部分,在HotSpot虛擬機中分為新生代和老年代,新生代又分為Eden區和Survivor0區、Survivor1區。
內存 :新生代+老生代+持久代。在我們垃圾回收的時候,我們往往將堆內存分成新生代和老生代(大小比例1:2),
新生代中由Eden和Survivor0,Survivor1組成,三者的比例是8:1:1,新生代的回收機制采用復制算法,在Minor GC的時候,我們都留一個存活區用來存放存活的對象,真正進行的區域是Eden+其中一個存活區,當我們的對象時長超過一定年齡時(默認15,可以通過參數設置),將會把對象放入老生代,當然大的對象會直接進入老生代。
老生代采用的回收算法是標記整理算法。
( 新生代+老生代+持久代 :https://www.cnblogs.com/Jomini/p/13798248.html )
方法區:
JVM用來存儲加載的類信息、常量、靜態變量、編譯后的代碼等數據。不同虛擬機有不同的實現,oracle的HotSpot在Java7中方法區放在永久代,Java8中方法區放在元空間,並通過GC機制來管理。
也稱”永久代“,它用於存儲虛擬機加載的類信息、常量、靜態變量、是各個線程共享的內存區域。默認最小值為16MB,最大值為64MB(64位JVM由於指針膨脹,默認是85M),可以通過-XX:PermSize 和 -XX:MaxPermSize 參數限制方法區的大小。它是一片連續的堆空間,永久代的垃圾收集是和老年代(old generation)捆綁在一起的,因此無論誰滿了,都會觸發永久代和老年代的垃圾收集。不過,一個明顯的問題是,當JVM加載的類信息容量超過了參數-XX:MaxPermSize設定的值時,應用將會報OOM的錯誤。參數是通過-XX:PermSize和-XX:MaxPermSize來設定的。
非線程共享
虛擬機棧:
描述的是java方法執行的內存模型:每個方法被執行的時候都會創建一個”棧幀”,用於存儲局部變量表(包括參數)、操作棧、方法出口等信息。
每個線程私有的空間,由多個棧幀組成,一個方法對應一個棧幀,棧幀包括局部變量表、操作數棧、動態鏈接、方法返回地址、附加信息等。棧內存默認最大1M,超出跑出StackOverFlowError。
棧幀 組成:局部變量區、操作數棧、幀數據區
局部變量表: 存放了編譯器可知的各種基本數據類型、對象引用(引用指針,並非對象本身),其中64位長度的long和double類型的數據會占用2個局部變量的空間,其余數據類型只占1個。局部變量表所需的內存空間在編譯期間完成分配,當進入一個方法時,這個方法需要在棧幀中分配多大的局部變量是完全確定的,在運行期間棧幀不會改變局部變量表的大小空間。
本地方法棧:
類似虛擬機棧,是為虛擬機使用native本地方法而准備的。具體實現由虛擬機廠商來實現。HotSpot虛擬機中實現與虛擬機棧一致,同時超出大小拋StackOverFlowError。
程序計數器:
記錄當前線程執行字節碼的位置,存儲的是字節碼指令地址,如果native方法,則為空。CPU同一時間只能執行一條線程中的指令,線程切換后通過程序計數器來恢復正確的執行位置。
------------------------------------------------------------------
參考:
https://blog.csdn.net/qq_41297896/article/details/89949632
https://blog.csdn.net/zengxiantao1994/article/details/89303290
https://zhuanlan.zhihu.com/p/92341957
https://www.cnblogs.com/itsharehome/p/11290907.html