JVM一些體會

一、從小例子開始

環境是
java version “1.8.0_191”
Java™ SE Runtime Environment (build 1.8.0_191-b12)
Java HotSpot™ 64-Bit Server VM (build 25.191-b12, mixed mode)

openjdk version “1.8.0_191”
OpenJDK Runtime Environment (build 1.8.0_191-8u191-b12-2ubuntu0.16.04.1-b12)
OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode)

首先有個簡單的垃圾回收的例子,

class TestGC{
    public static void main(String[] args) {
        new TestGC();
        System.gc();//顯式調用Full GC(),給出一個回收新老生代的信號(注意,不是一定會回收,因爲jvm也會偷懶),一般是自動的,這裏作爲展示而手動觸發
        System.runFinalization();   //強制調用對象的終結方法,這裏纔是真的銷燬(事無絕對,隱式調用gc()時,有的對象如果在二次標記時找回組織,可以繼續存活)
    }
}

編譯後查看GC

下圖環境是windows的HotSpot jdk8

jdk8(圖1)
查看詳細java堆使用情況(java非標準命令可以參考oracle官方解釋
java -XX:+PrintGCDetails -XX:+UseG1GC
解釋一下上面的命令,就是在使用G1垃圾回收器的情況下,打印垃圾回收細節(加上過打印時間戳,不過沒效果)
圖2(圖2)

下圖環境是Ubuntu下的openjdk8
在這裏插入圖片描述(圖3)
在這裏插入圖片描述(圖4)
對比之後,結果非常有意思。

類型 Full GC G1 GC
jdk 內存佔用小,耗時長 堆內存佔用少,時間未知
openjdk 內存佔用大,耗時短 堆內存佔用太多,時間未知

補充一下什麼是Full GC?

minor GC:只回收年輕代YoungGen(包括Eden,Survivor),但是從圖2、圖4發現young和survivors是分開的,所以這就有意思了。
Major GC: 只清理老生代。不過這個定義不太合適,因爲不會僅僅清理老生代,且常常由minor GC觸發,這兩個不能分的太開。
Full GC: 清理全部。

二、G1涉及術語

1、Metaspace

這裏改動很大,原來jdk7中還有永久代PermGen,而這裏jdk8完全移除了,轉爲使用元空間Metaspace。

官方JDK8 HotSpot JVM解釋是因爲要和JRockit 融合而完成的一個小目標。

Hotspot JVM使用本地內存來存儲類元數據信息並稱這塊區域爲元空間Metaspace。相比以往PermGen,元空間擴容更容易,可以容納更多的類數據。

2. Mixed GC Event

這是混合GC事件。注意看開頭寫的環境信息,其中包含build 25.191-b12, mixed mode,這就表明JVM默認爲混合模式。在這個時間內部,所有的年輕代region和一部分老年代region一起回收。

3. Region

G1收集器將堆進行分區,劃分爲一個個區域,每次收集的時候,選擇部分區域,以此控制垃圾回收產生的停頓時間,這個區域就是region,也稱作堆區。通常劃分爲三個區域Eden、Survivor、Old,而Survivor也可以劃分爲From和To區域。

4. Reclaimable

G1 GC爲了能夠回收對象,而創建出一系列專門用於存放這些回收對象的堆區region。這些region都在一個鏈表隊列中,存活率由-XX:G1MixedGCLiveThresholdPercent界定。

5. RSet

全稱是Rememberd Set,存儲不同region之間對象的相互引用,參與遍歷region根時的引用可達性分析。HotSpot中用來記錄這個的數據結構是OopMap。這樣會使各個分區的GC更加獨立。

6. CSet

全稱是Collection Set,保存一次GC中將被執行垃圾回收的region。GC時,在CSet中所有的存活數據(Live Data)都會被轉移(複製/移動)。堆區可以是Eden,Survivor和/或Old Generation,也可以都不是,即爲空白分區,region的概念比Eden之類更小,換句話說,Eden會有很多個region。region的大小是一致的,是連續的虛擬內存塊,且CSet佔JVM內存不能超過1%。

7. G1 Pause Time Target

就是G1停頓目標時間,因爲GC是獨佔式的,所以會引起應用程序停頓,這個停頓時間就是設置的期望時間。在G1中使用了停頓預測模型去預測用戶設定的目標停頓時間,並基於這個時間進行垃圾回收。

8. PLAB

Promotion Local Allocation Buffers,用於年輕代回收。其作用是避免多線程競爭相同的資源,每個線程擁有獨立的PLAB,用於針對Survivor和Old。這裏說個題外話,對象初次創建在Eden中爲Allocation,然後因爲存在時間較長,慢慢promoting到Survivor,再就是Old。這兩個Allocation和Promotion在用法上有相同的含義。

9. TLAB

Thread Local Allocation Buffers,即線程本地分配緩存,是一個線程專用的內存分配區域。避免對象分配時的多線程競爭產生衝突。對於G1來說,TLAB是Eden的一個Region,單一線程使用它分配資源。主要用途是讓一個線程通過棧操作的方式獨享內存空間,用於對象分配,這樣比多個線程之間共享要快很多。

三、JVM內存模型

這個很重要,但是很多人寫得很好,不贅述,直接給出引用。
https://blog.csdn.net/u011552404/article/details/80306316
https://blog.csdn.net/wangshuminjava/article/details/80921305
因爲模型這個東西是一個框架,理解了就知道jvm的整體運行機制,細節還是需要推敲。

四、G1 GC

G1是在jdk7中正式出現的全新垃圾回收器,從長期願景來看,它是爲了取代CMS回收器。它仍然區分年輕代和老年代,但堆的結構進行調整,不要求整個Eden區、年輕代或者老年代包含的Region區在物理上都是連續的。全新的分區算法,其特點有:
並行性(多個GC線程同時工作)、併發性(與應用程序線程交替執行)、空間整理(不同於CMS的標記-清理和多次GC後才碎片整理,G1每次GC都會整理)、可預見性(由於分區,G1只選擇部分區域進行回收,不再是整體的大堆塊)

G1的並行循環

包括以下活動:初始標記、並行Root區間掃描、並行標記、重標記和清理。除了最後的清理階段,其他都屬於標記存活對象階段。
1、初始標記階段,收集所有GC根。獨佔式的。
2、並行Root區間掃描必須掃描和標記所有幸存者區間的對象引用,應用程序也可以並行執行,不過有時間約束,即必須在下一個GC開始前結束。
3、並行標記階段,這裏基本上完成全部的標記工作。利用多線程並行標記存活對象及對應的邏輯地圖,但是應用程序吞吐量會有所下降。
4、重標記階段是一個獨佔式階段,通常是一個很短的停頓,到此完成所有標記工作。
5、清理階段,沒有包含存活對象的region會被回收,並加入到可用region隊列。

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