JVM最新發展
周志明老師在2020年1月更新併發布了經典書《深入理解Java虛擬機》第三版,此版距第二版出版已過去七八年。在新書中,老師加入了許多JVM自JDK8以後出現的新特性與新概念。JVM虛擬機內存管理方面,也有所更新。
在此我略微整理了下書中的概念,並做了思維導圖,供以後學習
一、思維導圖
1. JVM內存區域
2. 內存涉及概念
3. JVM處理Java對象
可參考文章《JVM處理Java對象-------思維導圖》
4. OutOfMemoryError
可參考文章:《OutOfMemoryError分析-------思維導圖》
二、導圖提綱
線程私有
以下三個區域爲線程私有的內存區域
- 隨線程的啓動和結束而銷燬
- 每個線程都會創建屬於自己的線程私有區域 也就是說計數器、棧在JVM中可能不唯一
1. 程序計數器
- 一塊較小的內存空間
- 類似於當前進程所執行的行號指示器
- 通過改變此計數器的值,程序實現了以下控制邏輯:
3.1. 分支
3.2. 循環
3.3. 跳轉
3.4. 異常處理- 當單核CPU實現多線程任務、來回切換線程執行時,也需要利用此計數器來實現
- 唯一一個沒有OutOfMemoryError的區域
2. Java虛擬機棧 (Java VM Stack)
- 本身就是一個數據結構的棧Stack,先入先出
- Java VM Stack描述的是Java方法在執行時的線程內存模型
- 當每個方法被執行時,會爲之創建一個棧幀
- 棧幀
- 局部變量表
- 操作數棧
- 動態連接
- 方法出口
- 每個方法的slot (局部變量槽) 是完全確定的, 也就是說此部分需要申請多少內存完全確定
- 每個方法從被調用至執行完返回,對應着它的棧幀壓棧入頂,最終出棧的過程
- 會出現StackOverflowError與OutOfMemoryError
(Hotspot不會有後者,當內存不夠時,它會認爲是深度不能滿足了)- 虛擬機參數:-Xss
3. 本地方法棧
- 與Java虛擬機棧非常像,也是一個棧
- 描述的是Java調用本地Native服務(操作系統或其他程序提供的服務) 的線程內存模型
- 有些虛擬機(如Hotspot)會將Java虛擬機棧與本地方法棧合二爲一,不嚴格區分
- 會出現OutOfMemoryError
線程共享
以下爲線程共享的內存塊:
- 在JVM啓動,或者需要使用時分配
- 線程無關、所有線程共享內存
4. Java堆 (GC Heap)
1唯一目的:存放對象實例
2. 內存最大的區域,內存上可以不連續,但邏輯上應該被視爲連續
3. 虛擬機垃圾回收最主要的戰鬥區域
4. 所有線程共享此區域,爲提升對象分配效率以及垃圾 回收效率,可以劃分出多個線程私有的分配緩衝區(TLAB)
5. 會出現OutOfMemoryError
6. 虛擬機參數:-Xmx -Xms
5. 方法區 (Non-Heap)
- 存儲內容
- 類型信息
- 常量
- 靜態變量
- JIT編譯後的代碼緩存
- 傳說中的"永久代"
- JRocket、J9等虛擬機,都沒有永久代
- Hotspot在JDK7之前有,8之後廢棄
- JDK8之後的實現方式:採用本地內存(Native Memory), 元空間(MetaSpace) 不受JVM的內存限制;
- 可以不用垃圾回收,但主流虛擬機都會支持 主要是對常量池的回收以及對類型的卸載
- 會出現OutOfMemoryError
- 虛擬機參數:JDK8之後,-XX:MaxPermSize參數不再有效
-XX: MetaspaceSize、-XX: MaxMetaspaceSize成爲有用控制
6. 運行時常量池
- 屬於方法區的一部分
- Class文件中的**“常量池表”**,會被虛擬機加載映射到此區域儲存
- 並非只有Class常量池表纔可以進入運行時常量池;運行期間也可會將新的常量放到池中,例如String.intern()方法
- 會出現OutOfMemoryError
7. 直接內存
- 並不是在虛擬機JVM內存中
- 通過Native函數庫,直接分配本地內存(本機直接內存)
3… Java內一般保有這個直接內存的引用,以便對其操作- 會受到本機物理內存等物理限制,當物理內存、swap分區等空間不夠時, 也會拋出OutOfMemoryError