JVM記憶體結構
主要是看jvm的運作時資料區
運作時資料區主要分為5個部分:
- 方法區
- 堆區
- 虛拟機棧
- 本地方法棧
- 程式計數器
1、方法區
這個區主要存放一些 類型資訊、域資訊、方法資訊、JIT即時編譯代碼緩存 和 運作時的常量。
該區在jdk7及之前,是包含在JVM記憶體中的一部分,叫永久代(PermGen)。
在jdk7之後,就把這一塊移到了JVM記憶體之外,變成了元空間(MetaSpace)。不受JVM記憶體控制,隻受機器本身的記憶體限制。可以設定區域的記憶體大小。
2、堆區
這個區域存放所有的 對象 資訊。
該區域可以分為兩部分:年輕代 和 老年代。
年輕代又可以分為:Eden區 、 Survivor0區(簡稱S0區) 和 Survivor1區(簡稱S1區)。
具體劃分如下圖:
預設記憶體大小比例:
年輕代:老年代=1:2
Eden:Survivor0:Survivor1=8:1:1
當對象在建立時,首先先放入到Eden區。如果出現了大對象,Eden區記憶體不夠容乃該對象時,考慮直接放入 老年代。
當Eden區記憶體不夠時,會先嘗試将對象放入S0區域中,如果S0也記憶體不足,則進行一次Minor GC(YoungGC/年輕代GC)。此時将存活對象由Eden區域 和 S0區 放入到S1區。如果S0區中有對象存活時間大于了最大存活時間的門檻值(threshold),則将該對象晉升到老年代中。
當老年代記憶體也到達預警記憶體大小時,則會進行Full GC(MajorGC/全局GC)。此時會回收堆中所有區域。如果FullGC之後還放不下對象時,就會報OOM。
FullGC時,需要Stop the World,是以此時會對程式運作有較大停頓。避免頻繁的FullGC也是程式需要優化的一個很關鍵的點。
3、虛拟機棧區
虛拟機棧區中是一個一個的棧,棧中是一個一個的棧幀。一個虛拟機棧對應的是一個線程,一個棧幀對應的是一個方法。
棧幀中包含:局部變量表、操作數棧、方法傳回位址、動态連結 和 一些附加的資訊。
局部變量表: 主要儲存函數的參數以及局部的變量資訊。
操作數棧:可以了解為一個用于計算的臨時存儲資料的區域。
方法傳回位址:存放調用該方法的PC寄存器(程式計數器)的值,方法在退出時會去找程式計數器,然後進行下一步的調用。
動态連結:由于java語言的多态性,有些變量在運作期間才會确定下來具體屬于哪個類。是以這個動态連結就是指向目前變量或者對象真正的類。
附加資訊:棧幀中還允許攜帶與java虛拟機實作相關的一些附加資訊。例如,對程式調試提供支援的資訊。
4、程式計數器
記錄程式執行的順序,可以看做是目前線程所執行的位元組碼的行号訓示器。
5、本地方法棧
存放一些本地(native)方法,便于JVM程式調用。
GC(垃圾回收)
垃圾回收的算法
垃圾确認算法: 引用計數法 和 可達性分析算法
垃圾回收算法: 複制算法、标記清除算法、标記壓縮算法、分代收集算法、增量收集算法、分區算法
7種垃圾回收器:SerialGC、SerialOldGC、ParNewGC、ParallelGC、ParallelOldGC、CMS、G1。
如圖中所示,實線部分是可以配合使用的,虛線部分是之前可以配合使用,之後去除掉不可以配合使用的。
1、SerialGC 和 SerialOldGC 串行回收器
串行回收器,采用複制算法,适用于單CPU的機器,在沒有線程切換的時候,回收效率比較高。
SerialGC是主要針對年輕代的回收。
SerialOldGC是回收老年代的垃圾回收器。
2、ParNewGC 并行回收器
一種支援多線程的垃圾回收器,采用複制算法,在多核機器中使用,能更好的展現多核的高效性。運作效率比串行的更好一些。
3、ParallelGC 和 ParallelOldGC 并行回收器
一個适用于年輕代一個适用于老年代。
ParallelGC 采用複制算法,并行回收機制。
ParallelOldGC 采用标記壓縮算法,并行回收機制。
與ParNew相比,達到了 可控制吞吐量 和 自适應調節政策。
4、CMS (Concurrent Mark Sweep)并發垃圾回收
實作了最小停頓垃圾回收。
1、初始标記
隻标記GC Roots直接指向的對象。需要Stop-the-World。
2、并發标記
通過GCRoots初始标記一次垃圾。不需要Stop-the-World。
3、重新标記
最終再标記一次不被引用的對象。主要是重新掃描之前并發處理階段的所有殘留更新對象。不需要Stop-the-World。
4、并發回收
與正常程式一起并發執行,不需要Stop-the-World,減少了系統停頓時間,但是吞吐量會稍微有所下降。
5、G1 分區垃圾回收器
G1與其他4個都不同。G1垃圾回收把堆區分為了很多個小的區域,每個區域的存儲對象是不定的。一個區域可能現在存的是年輕代的對象,等下次回收之後,可能存的就是老年代的對象。
存儲和回收都是分塊的進行,可預測可控的停頓時間。在實作較短停頓時間的同時,可以對應用程式有較小的影響。
面向服務端應用,針對具有大記憶體、多處理器的機器。
一些零碎知識點
1、雙親委派機制:
類加載流程:
1)如果一個類加載器收到了類加載請求,它并不會自己先去加載,而是把這個請求委托給父類的加載器去執行;
2)如果父類加載器還存在其父類加載器,則進一步向上委托,依次遞歸請求最終将到達頂層的啟動類加載器;
3)如果父類加載器可以完成類加載任務,就成功傳回,倘若父類加載器無法完成此加載任務,子加載器才會嘗試自己去加載,這就是雙親委派模式。
優點
避免類的重複加載
保護程式安全,避免核心API被篡改
2、棧頂緩存技術
将棧頂元素全部緩存在實體CPU的寄存器中,以此降低對記憶體的讀/寫次數,提升執行引擎的執行效率。
3、空間配置設定擔保
在發生MinorGC之前,虛拟機會檢查老年代的最大可用連續空間是否大于新生代所有對象的總空間。
如果大于,則此次MinorGC是安全的。
如果小于,則看是否開啟了空間配置設定擔保。
如果開啟了,就會檢查 老年代最大可用連續空間 是否大于 曆次晉升到老年代的對象的平均大小。
如果大于,則嘗試進行一次MinorGC,此次MinorGC是有風險的。
如果小于,則進行一次FullGC。
如果沒有開啟空間配置設定擔保,則直接進行FullGC。
4、逃逸分析
分析棧幀中的對象或者變量是否隻在目前方法中使用。
如果隻在目前方法中使用,則沒有發生逃逸。否則發生了逃逸。
5、棧上配置設定 、 标量替換 、同步省略
當對象或者變量沒有發生逃逸的時候,會使用棧上配置設定和标量替換進行優化。
棧上配置設定
将堆配置設定轉化為棧配置設定。如果一個對象在子程式中被配置設定,要使指向該對象的指針永遠不會逃逸,對象可能是棧配置設定的候選,而不是堆配置設定。
同步省略(鎖消除)
如果一個對象被發現隻能從一個線程被通路到,那麼對于這個對象的操作可以不考慮同步。
分離對象或标量替換
有的對象可能不需要作為一個連續的記憶體結構存在也可以被通路到,那麼對象的部分(或全部)可以不存儲在記憶體,而是存儲在CPU寄存器中。