JVM內存模型詳細解析

JVM內存模型詳情解析

一、結構圖

在這裏插入圖片描述

NOTE: string常量池 存在 堆內存中

二、各部分詳情解析

1、堆
1)老年代

對象年齡(經過一次 monitor GC 年齡加1) >15 的會存到 老年代

2)年輕代
  • eden
    • 內存分配默認是 年輕代 80%
  • survivor
    • 內存分配默認是 年輕代20%(from 和 to 區分別佔10%)
3)常量池:

​ String常量 存儲在堆中

2、虛擬機棧
1)局部變量表
  • 存儲的數據:存放方法參數和方法內定義的局部變量
  • note:局部變量表的容量以變量槽(Variable Slot)爲最小單位,Java程序編譯爲Class文件時,就在方法的Code屬性中的max_locals數據項中確定了該方法所需分配的局部變量表的最大容量。(最大Slot數量)
2)操作數棧
  • 存儲的數據
    • 和局部變量區一樣,操作數棧也是被組織成一個以字長爲單位的數組。但是和前者不同的是,它不是通過索引來訪問,而是通過標準的棧操作—壓棧和出棧—來訪問的
  • note:操作數棧的最大深度也在編譯的時候寫入到方法的Code屬性max_stacks數據項中,操作數棧的深度都不會超過max_stacks中設置的最大值。
3)動態鏈接
  • **介紹:**Java 是在運行期間動態鏈接的,所以爲了支持動態鏈接,需要將方法區裏面的符號引用轉爲直接引用(即:給出地址),這就叫動態鏈接
4)方法出口信息

note:棧中每一個線程 都會創建自己的 棧幀,每個棧幀中又會分爲以上四種信息

源碼及字節碼解析棧
3、本地方法棧

和虛擬棧類似,只是存儲native修飾的 方法信息

4、元數據區/元空間
1)類信息
2)靜態變量
  • static修飾的變量
3)常量池
  • 常量池在java用於保存在編譯期已確定的,已編譯的class文件中的一份數據。它包括了關於類,方法,接口等中的常量,也包括字符串常量,如String s = "java"這種申明方式;當然也可擴充,執行器產生的常量也會放入常量池,故認爲常量池是JVM的一塊特殊的內存空間。

  • Java是一種動態鏈接的語言,常量池的作用非常重要,常量池中除了包含代碼中所定義的各種基本類型(如int、long等等)和對象型(如String及數組的常量值外,還包含一些以文本形式出現的符號引用,比如:

    ​ 類和接口的全限定名;

    ​ 字段的名稱和描述符;

    ​ 方法的名稱和描述符。

    在C語言中,如果一個程序要調用其它庫中的函數,在鏈接時,該函數在庫中的位置(即相對於庫文件開頭的偏移量)會被寫在程序中,在運行時,直接去這個地址調用函數;

    而在Java語言中不是這樣,一切都是動態的。編譯時,如果發現對其它類方法的調用或者對其它類字段的引用的語句,記錄進class文件中的只能是一個文本形式的符號引用,在連接過程中,虛擬機根據這個文本信息去查找對應的方法或字段。

    所以,與Java語言中的所謂“常量”不同,class文件中的“常量”內容很豐富,這些常量集中在class中的一個區域存放,一個緊接着一個,這裏就稱爲“常量池”。

  • class文件共有11種常量表

常量表類型 標誌值(佔1 byte) 描述
CONSTANT_Utf8 1 UTF-8編碼的Unicode字符串
CONSTANT_Integer 3 int類型的字面值
CONSTANT_Float 4 float類型的字面值
CONSTANT_Long 5 long類型的字面值
CONSTANT_Double 6 double類型的字面值
CONSTANT_Class 7 對一個類或接口的符號引用
CONSTANT_String 8 String類型字面值的引用
CONSTANT_Fieldref 9 對一個字段的符號引用
CONSTANT_Methodref 10 對一個類中方法的符號引用
CONSTANT_InterfaceMethodref 11 對一個接口中方法的符號引用
CONSTANT_NameAndType 12 對一個字段或方法的部分符號引用

(1) CONSTANT_Utf8 用UTF-8編碼方式來表示程序中所有的重要常量字符串。這些字符串包括: ①類或接口的全限定名, ②超類的全限定名,③父接口的全限定名, ④類字段名和所屬類型名,⑤類方法名和返回類型名、以及參數名和所屬類型名。⑥字符串字面值

表格式: tag(標誌1:佔1byte) length(字符串所佔字節的長度,佔2byte) bytes(字符串字節序列)

(2) CONSTANT_Integer、 CONSTANT_Float、 CONSTANT_Long、 CONSTANT_Double 所有基本數據類型的字面值。比如在程序中出現的1用CONSTANT_Integer表示。3.1415926F用 CONSTANT_Float表示。

表格式: tag bytes(基本數據類型所需使用的字節序列)

(3) CONSTANT_Class 使用符號引用來表示類或接口。我們知道所有類名都以 CONSTANT_Utf8表的形式存儲。但是我們並不知道 CONSTANT_Utf8表中哪些字符串是類名,那些是方法名。因此我們必須用一個指向類名字符串的符號引用常量來表明。

表格式: tag name_index(給出表示類或接口名的CONSTANT_Utf8表的索引)

(4) CONSTANT_String 同 CONSTANT_Class,指向包含字符串字面值的 CONSTANT_Utf8表。

表格式: tag string_index(給出表示字符串字面值的CONSTANT_Utf8表的索引)

(5) CONSTANT_Fieldref 、 CONSTANT_Methodref、 CONSTANT_InterfaceMethodref 指向包含該字段或方法所屬類名的 CONSTANT_Utf8表,以及指向包含該字段或方法的名字和描述符的 CONSTANT_NameAndType 表

表格式: tag class _index(給出包含所屬類名的CONSTANT_Utf8表的索引) name_and_type_index(包含字段名或方法名以及描述符的 CONSTANT_NameAndType表 的索引)

(6) CONSTANT_NameAndType 指向包含字段名或方法名以及描述符的 CONSTANT_Utf8表。

  • 八種基本類型的包裝類和對象池

    java中基本類型的包裝類的大部分都實現了常量池技術,這些類是Byte,Short,Integer,Long,Character,Boolean,另外兩種浮點數類型的包裝類則沒有實現。另外Byte,Short,Integer,Long,Character這5種整型的包裝類也只是在對應值小於等於127時纔可使用常量池,也即對象不負責創建和管理大於127的這些類的對象。

5、程序計數器
1)線程執行到的行號,native方法 行號爲 null

三、內存溢出

會產生內存溢出的區域
  1. 元數據區(元空間)

note:只有程序計數器不會出現內存溢出

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章