這是我參與8月更文挑戰的第4天,活動詳情查看:8月更文挑戰html
JVM(Java Virtual Machine):爪哇虛擬機java
JVM內存結構:運行時數據區域git
事實上,對於JVM上層,還存在一個由Oracle定製的Java虛擬機規範,咱們常說的JVM通常是指具體的某個JVM規範的具體實現。好比咱們常用的Java虛擬機HotSpot,JDK1.8使用的就是HotSpotweb
> java -version
java version "1.8.0_271"
Java(TM) SE Runtime Environment (build 1.8.0_271-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.271-b09, mixed mode)
複製代碼
好比咱們常常搞混的,JDK1.8以前的永久代、JDK1.8以後的元空間,這篇文章是永久代,到了那篇文章又是元空間的,實際上他們兩個均可以看做是JVM規範中方法區的實現數組
本文針對JVM的內存區域,儘量詳細的解剖緩存
事實上,JVM的知識多且雜,容易混淆,對此,我強烈建議你點贊收藏加關注,逛完
PB站,趁着精神狀態良好,來複習一遍JVM想必也是極好服務器
JVM內存區域,又稱運行時數據區域,就是下圖紅框框起來的部分:markdown
JVM總體架構圖:數據結構
主要分爲如下區域:架構
程序計數器是一塊較小的內存空間,能夠看做是當前線程所執行的字節碼的**行號指示器;**它是惟一一個在 JVM 規範中沒有規定任何
OutOfMemoryError
狀況的區域
當多個線程在特定的時間內同時執行的時候,一個線程不可能一直佔用着CPU 的資源,這樣就會形成頻繁的上下文切換,爲了線程切換回來後,能恢復到正確的位置繼續執行,每一個線程都有本身的程序計數器
字節碼解釋器工做時就是經過改變這個計數器的值來選取下一條須要執行的字節碼指令,從而實現代碼的流程控制,如:順序執行、選擇、循環、異常處理等
任什麼時候間一個線程都只有一個方法在執行,也就是所謂的當前方法。若是當前線程正在執行的是 Java 方法,程序計數器記錄的是 JVM 字節碼指令地址,若是是執行 native 方法,則是未指定值(undefined)
每一個線程在建立的時候都會建立一個虛擬機棧,其內部保存一個個的棧幀,每一次方法調用都會有一個對應的棧幀被壓入棧中,每個函數調用結束後,都會有一個棧幀被彈出,遵循「先進後出/後入先出」的原則
以下圖,方法1調用了方法2,因而方法2把方法1壓在了身下,這個過程就是壓棧;當前方法執行完畢後(return或者異常),就會進行出棧操做
虛擬機棧裏面保存棧幀,每一個棧幀中保存了方法的局部變量表、操做數棧、動態連接、方法出口信息
在這裏大概說一下棧裏面的幾個東西是幹嗎的,詳細內容下回分解
String abc = "abc"
;對象引用(reference 類型,它不一樣於對象自己,多是一個指向對象起始地址的引用指針,也多是指向一個表明對象的句柄或其餘與此對象相關的位置)return
退出時,調用者的 PC 計數器的值做爲返回地址,即調用該方法的指令的下一條指令的地址;經過異常退出的,返回地址是要經過異常表來肯定的,棧幀中通常不會保存這部分信息虛擬機棧的內存大小能夠是動態的,也能夠是固定大小的
StackOverFlowError
:當設置爲固定大小時,如果壓棧超出了最大的容許值就會拋出該異常OutOfMemoryError
:當設置爲動態擴展時,如果擴展時沒法向系統申請到足夠的內存時會報該異常本地方法棧的功能與虛擬機棧相似,會拋出的異常也同樣,二者的區別在於,虛擬機棧是爲Java方法服務的,而本地方法棧是爲Native方法服務的
並非全部 JVM 都支持本地方法。由於 Java 虛擬機規範並無明確要求本地方法棧的使用語言、具體實現方式、數據結構等。若是 JVM 產品不打算支持 native 方法,也能夠無需實現本地方法棧
在 Hotspot JVM 中,直接將本地方法棧和虛擬機棧合二爲一
Java 虛擬機所管理的內存中最大的一塊,Java 堆是全部線程共享的一塊內存區域,在虛擬機啓動時建立。此內存區域的惟一目的就是存放對象實例,幾乎全部的對象實例以及數組都在這裏分配內存,正因如此,Java 堆也是垃圾收集器管理的主要區域,所以也被稱做GC 堆(Garbage Collected Heap)
爲了高效的進行垃圾回收,能夠發現,堆被劃分紅了三個區域:
在啓動Java程序的時候,能夠用參數指定堆的大小:
-Xms
:設定堆的起始內存,默認狀況下,初始堆內存大小爲:電腦內存大小/64-Xmx
:設定堆的最大內存,默認狀況下,最大堆內存大小爲:電腦內存大小/4分享一個小zi si,咱們一般會將
-Xmx
和-Xms
兩個參數配置爲相同的值,其目的是爲了可以在垃圾回收機制清理完堆區後再也不須要從新分隔計算堆的大小,從而提升性能
例:
java -Xmx1024m -Xms1024m -jar test.jar
複製代碼
堆最容易出現 OutOfMemoryError
錯誤,有兩個比較常見的錯誤信息:
OutOfMemoryError: GC Overhead Limit Exceeded
:這是JVM在垃圾回收時用了太多時間而且回收的空間不多的時候會報出的錯誤OutOfMemoryError: Java heap space
:這是建立對象是,發現堆中的內存不足以存放新的對象就會出現這個報錯-XX:MaxTenuringThreshold
參數設置)方法區,是JVM規範定義的一個概念,不管是JDK1.8以前的永久代,仍是JDK1.8以後的元空間,都屬於規範的一種是實現。能夠把方法區看做Java代碼中的接口,而永久代和元空間則是它的具體實現
方法區用於存儲已被虛擬機加載的類型信息、常量、靜態變量、即時編譯器編譯後的代碼緩存等
-XX:MetaspaceSize
:設置元空間的初始大小-XX:MaxMetaspaceSize
:設置元空間的最大大小因爲元空間是直接使用系統的物理內存的,若是不指定元空間額度大小,隨着類的建立,虛擬機可能會耗盡全部的可用系統內存
一樣的,因爲元空間使用的是系統內存,雖然任有可能溢出,可是出現的機率會小不少,當元空間溢出時會報錯 OutOfMemoryError: MetaSpace
須要注意的是:
-XX:MetaspaceSize
的值爲20.75MB,這就是初始的高水位線,一旦觸及這個水位線,Full GC 將會被觸發並卸載沒用的類(即這些類對應的類加載器再也不存活),而後這個高水位線將會重置,新的高水位線的值取決於 GC 後釋放了多少元空間。若是釋放的空間不足,那麼在不超過 MaxMetaspaceSize
時,適當提升該值。若是釋放空間過多,則適當下降該值-XX:MetaspaceSize
設置爲一個相對較高的值。