《Java性能優化權威指南》學習筆記

編譯

編譯是指生成機器碼 即 二進制目標文件的過程。
Java最初是轉換爲類文件,虛擬機將其轉爲字節碼。
運行時動態的轉爲機器碼。

JIT會在運行時,將調用次數超過閾值CompileThreshold的代碼編譯(由方法調用計數器計數)。

JVM性能監控

重要的垃圾收集數據
堆大小。
新生代、老年代、永久代大小
Minor GC /Full GC 的持續時間、頻率、空間回收量

打印垃圾收集信息 -XX+PrintGCDetails

可以啓動時開啓, 也可用jinfo 動態開啓

常用GC啓動參數

推薦 -XX:+PrintGCDetails -XX:+PrintGCDateStamps-Xloggc:<filename> -XX:+UseConcMarkSweepGC -Xmx400m -Xms400m -Xmn30m -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:G:/學習/gclog.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=G:/學習/dump.hprof

資料:https://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html

-XX:PrintGCTimeStamps 打印gc的時候打印時間戳
-XX:+UseConcMarkSweepGC 使用cms垃圾回收器

-Xmn30m 新生代30M 默認 SurvivorRatio 8, eden:s0:s1爲8:1:1,所以新生代爲9,即30m*0.9=27m

MetaspaceSize 爲本地內存。 非堆。
-Xmx400m -Xms400m 最大堆內存 400M,最小堆內存400M, 老年代=400m-30m=370m

jmap -head jpsid
在這裏插入圖片描述

收集的時候打印時間戳

-XX:+PrintGCTImeStamps   啓動秒數
-XX:+PrintGCDateStamps  時間戳

內存分佈
圖片來源於網絡
Memory Pools
在這裏插入圖片描述

新生代

Minor GC
GC後 Eden幾乎是空的。
大多數新對象分配在Eden,大對象可能直接分配到老年代。
MonorailGC後 ,兩個Survivor交換角色。
“足夠老”的存活對象提升到老年代。
用到複製算法。
MinorGC過程中,Survivor(to)可能不足以容納Eden+另一個Survivor(from)中的存活對象。此時就需要將Surviv偶然中的存貨對象溢出?多餘的對象轉移到老年代–過早提升(Premature Promotion)。 — 如果老年代滿了,無法容納更大對象,minor GC後會導致Full GC.

Minor GC:Eden+to 存活對象–> to 不夠? ----> 老年代 不夠? ----> Full GC

老年代

“足夠老”的存活對象提升到老年代。

永久代

類加載 ,將類的源數據信息加載到永久代(jdk8以下)
永久代滿,引發垃圾收集-Full GC.
當需要加載其他類而空間不足,未使用的類就會從永久代中被卸載。
永久代垃圾回收不是stop-the-world
相關參數: -XX:PermSize 、 -XX:MaxPerSize

垃圾回收器

分代垃圾收集器

基於以下觀察事實:

  1. 大多數分配對象朝生夕死。
  2. 存活時間久的對象很少引用存活時間短的對象。
分代名稱 內存佔用 垃圾收集頻率 特點
新生代 minorGC,多次躲過回收後晉升到老年代
老年代 FullGC執行頻率低,但是執行時間長。儘量
永久代 廢棄常量和無用類

Serial收集器

只使用一個處理器
minor GC 、 Full GC都 stop-the-world.
標記清除、標記壓縮

適用於 對停頓時間要求不高,多個JVM實例在一臺機器上。

Parellel收集器-吞吐量

吞吐量大。
盡最大可能收集。
Minor GC 並行。
Full GC 並行。

CMS收集器-低延遲

停頓少,低延遲
減少stop-the-world時間。

初始標記 a 併發標記 b 重新標記 c 併發清除 d
短暫停頓,標記GC Roots可達對象① 標記可從①對象達到的存活對象 再次停頓,重新標記b階段導致未被標記的存活對象 清除整個Java堆

G1收集器-分代、垃圾優先

分代
優先回收垃圾最多的區域。

JVM性能調優

關注穩定狀態下 內存使用,程序延遲,吞吐量

選擇JVM運行模式

client、server

垃圾收集器

吞吐量、延遲、內存佔用 三選二

調整內存大小

調整JVM堆佈局

調整新生代、老年代、永久代大小

初始堆空間大小配置

名稱 設置參數 說明
Java堆 -Xms和-Xmx 3-4倍FullGC後老年代空間量
永久代 -XX:permSize和-XX:MaxPermSize 1.2-1.5倍~
新生代 -Xmn 1-1.5倍~
老年代 Java堆大小減新生代大小 2-3倍~

Survivor

Survivor太小,導致to無法存放所有從Eden空間和“From”空間複製來的活躍對象,導致提升到老年代。 加速老年代內存消耗,提前Full GC.

-XX:SurvivorRatio=<ratio>

ratio表示單個survivor空間與Eden空間大小的比率。
如果是8,則表示 from:to:eden = 1:1:8

所以調大Survivor需要降低ratio

survivor空間大小 = -Xmn/(-XX:SurvivorRatio=+2)

晉升

對象提升至老年代。
晉升閾值就是對象年齡。對象的年齡就是它所經歷的Minor GC次數。
【最大晉升閾值參數】-XX:MaxTenuringThreshold=<n>
對象年齡超過n值將其提升到老年代。

不建議將【最大晉升閾值】設置爲0,這會導致剛分配的對象,會在接下來的Minor GC中直接從新生代晉升到老年代,導致老年代空間迅速增長以至於Full GC。

不成熟的(未到年齡)的晉升解決方案是:使用SurvivorRatio增大Survivor空間

當Survivor空間比較緊張,JVM會使用一個低於 最大晉升閾值(MaxTenuringThreshold)的值來保證目標Survivor空間的佔用。

注意:Survivor空間過小,導致JVM 內部計算的閾值過小,導致易晉升到老年代,導致Full GC頻繁。

監控晉升閾值

參數:-XX:+PrintTenuringDistribution
期望Survivor大小 小於 活下來的對象。導致Survivor空間溢出,提升對象到老年代。

至少將Survivor增大到 【存活的Survivor大小】 

調整Survivor空間的容量

原則:調整Survivor空間的時候,如果新生代空間大小不變,增大Survivor則減少Eden。
因此,增大Survivor的同時,保持Eden空間不變,需要增大新生代空間。

理想狀態:晉升閾值等於最大晉升閾值

如果Minor GC時間過長,就要減少新生代空間大小。

調整目標Survivor空間佔用

嘗試Minor GC之後仍然維持的Survivor空間佔用

參數:-XX:TargetSurvivorRatio=<percent>

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