下面是我在網上找的JVM內存圖,非常直觀,貼在下面,供大家學習……
下面分別介紹一下圖中各個小方塊的作用和存的東西,能力有限,如果有錯誤,希望大家指正
PC寄存器
一塊很小的內存空間,用於記錄下一條CPU要運行的指令,各個線程之間是獨立擁有自己私人的PC寄存器的
- 當執行Java代碼時:存放的Java字節碼地址
- 當執行native方法時:則程序計數器爲空
JAVA虛擬機棧
這也是是線程私有的內存空間,和線程一起創建,它保存方法的局部變量、部分結果,並參與方法的調用和返回。
- 棧的大小可以設置爲動態擴展或者固定大小
- 可以使用 -Xss參數來設置棧的固定大小
- 如果超過固定大小,程序則會拋出StackOverflowError異常
- 如果設定爲動態擴展,超過內存範圍後,拋出OutOfMemoryError異常
棧幀
每個線程擁有獨立的棧,而每個棧中的元素就稱爲棧幀,棧幀保存上下文數據。在棧幀中,存放的信息有方法的局部變量表、操作數棧、動態鏈接方法和返回地址等信息
出入棧對應的操作
- 入棧:表示方法的調用
- 出棧:表示方法的返回
局部變量表
- 存放方法的參數和局部變量
- 如果需要在方法內進行回收一個局部變量,可以將這個變量其設置爲null或者在它超出範圍後 ,對其進行 “複用”
- 方法外的局部變量會自動回收
本地方法棧
本地方法棧和Java虛擬機棧的功能很相似,JAVA虛擬機用於管理JAVA函數的調用,而本地方法棧用於管理本地方法的調用,本地方法棧不是用Java實現的,而是用C實現的
Java堆
JAVA運行時內存中最重要的部分,幾乎所有的對象和數組都是在堆中分配空間的。java的堆分爲新生代和老年代兩部分,從開頭的圖中可以看出,他是被線程共享的
新生代
存放剛剛產生對象和年輕的對象,新生代有可以分爲以下3個空間:
- eden : 伊甸園,即對象的出生地,大部分對象剛剛建立時,通常會存放在這裏
- survivor space0 和 survivor space1 : 倖存者空間,又稱爲from space和to space,存放其中的對象是經歷過一次垃圾回收了的,並倖存下來的對象或者數組
老年代 (the space)
如果對象一直沒有被回收,生存的足夠長,到了指定年齡的對象就會被移入老年代。
方法區 :
類加載器,將硬盤中的class文件加載到內存的class content中,然後安裝JVM規範對class content進行解析,解析完後的對象(Class 對象),就放在方法區
- 方法區是一種規範,元空間是JDK8虛擬機中對方法區的一個具體的實現
- 可以通過MetaspaceSize、MaxMetaspaceSize調節大小(JDK8以前稱爲永久區)
- 將MetaspaceSize和MaxMetaspaceSize設置成一樣大,可以防止內存抖動,建議設置爲物理內存的
- JDK1.8以後,方法區的具體實現有永久區改爲了元空間,而元空間數據是放在本地內存中,而非JVM內存,這樣有利於存放更多更大的元數據
元數據
主要是class類中的各種信息,可以將他們分類如下:
類型信息
包括類的完整名稱、父類的完整名稱、類型修飾符(public/protected/private)、類型的直接接口類表
常量池
包括這個類方法、域等信息所引用的常亮信息,只要常亮池中的類沒有被任何地方引用,就可以被回收。
域信息
包括域名稱、域類型、域修飾符
方法信息
包括方法名稱、返回類型、方法參數、方法修飾符、方法字節碼、操作數棧、方法幀棧的局部變量區大小、異常表。
回收的條件
- 所有該類的實例被回收
- 且裝載該類的ClassLoader被回收
總結
上面的知識可能有些零散和晦澀,瞭解JVM的存放,可以讓我們理解代碼運行的邏輯,上面知識如有問題或者我有其他的新發現,我會及時更新