轉載自:掘金網【小妍品品】-JDK8之MetaspaceSize配置導致頻繁FullGC
前言
新系統上線,由於測試環境機器配置太低,所以單獨找了一臺預發機做接口壓測,但是QPS達到30時候cpu就滿了,簡直慌了,新系統這麼垃圾的麼~
背景介紹
新的賬務系統,角色定位是內部戶機構賬,所以根據不同的金融交易場次會有一次記賬請求中存在多借多貸,也就是一次請求會出現給18個賬戶在一個事務中做記賬處理,可想這裏面會有多少要注意的坑,詳細的不做展開
找問題
top 命令
因爲這個接口實現上多次用到數據庫悲觀鎖select for update,最初還以爲是代碼程序性能低導致的。但是看下qps才30… 涼了~
top -Hp pid 發現下面均是某個進程cpu使用率高
找到該pid下cpu佔用最高的tid,然後通過 jstack pid | grep tid -A 30 找到對應的進程信息
printf ‘%x\n’ 12149 tid 轉換16進制
jstack pid | grep tid 查看該線程信息。好了,不用往下瞅了,FullGC的進程~
jstat -gcutil pid 1000 10
這時候看到新生代、老年代的佔用率都非常低,但是還是在不斷的FullGC (這時候其實是知識點的缺失,平常沒有過於去關注M、CCS這兩列的值,想當然認爲這是某項指標的適用率,因爲佔比90%左右,所以沒有太在意~) ,單單看新老代的數據不應該會觸發FullGC啊!!!
然後稀裏糊塗的把堆詳細信息都給打出來了~,看下依舊不是這塊問題(使用率確實非常低)。
jmap -heap pid
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 1073741824 (1024.0MB)
NewSize = 235929600 (225.0MB)
MaxNewSize = 235929600 (225.0MB)
OldSize = 837812224 (799.0MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 134217728 (128.0MB)
CompressedClassSpaceSize = 125829120 (120.0MB)
MaxMetaspaceSize = 134217728 (128.0MB)
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
New Generation (Eden + 1 Survivor Space):
capacity = 212336640 (202.5MB)
used = 0 (0.0MB)
free = 212336640 (202.5MB)
0.0% used
Eden Space:
capacity = 188743680 (180.0MB)
used = 0 (0.0MB)
free = 188743680 (180.0MB)
0.0% used
From Space:
capacity = 23592960 (22.5MB)
used = 0 (0.0MB)
free = 23592960 (22.5MB)
0.0% used
To Space:
capacity = 23592960 (22.5MB)
used = 0 (0.0MB)
free = 23592960 (22.5MB)
0.0% used
concurrent mark-sweep generation:
capacity = 837812224 (799.0MB)
used = 95685920 (91.25320434570312MB)
free = 742126304 (707.7467956542969MB)
11.420926701589877% used
41909 interned Strings occupying 5041832 bytes.
還在一臉懵逼 ··· ···
這時候有個小夥伴提到了元空間內存滿了,恍惚,回過頭去查了下 M、CCS 明明是93.19%、90.48% 怎麼就滿了呢??
那麼jstat -gcutil 命令展示列的 M、CCS 到底是啥? 好吧把定義貼出來:
column {
header "^M^" /* Metaspace - Percent Used */
data (1-((sun.gc.metaspace.capacity - sun.gc.metaspace.used)/sun.gc.metaspace.capacity)) * 100
align right
width 6
scale raw
format "0.00"
}
column {
header "^CCS^" /* Compressed Class Space - Percent Used */
data (1-((sun.gc.compressedclassspace.capacity - sun.gc.compressedclassspace.used)/sun.gc.compressedclassspace.capacity)) * 100
align right
width 6
scale raw
format "0.00"
}
也就是說M是表示metaspace的使用百分比??事實證明並非如此~
通過jstat -gccapacity pid 看下具體的metaspace空間值,如下圖:
jstat -gccapacity pid
MC空間大小是131072KB=128M 然後通過 jstat -gc pid 發現 MC(元空間大小)、MU(元空間使用大小)兩列的值居然都不是是131072(此處沒截圖)。
說明:下面兩張圖是預發環境配置修改後的數值,跟當時定位問題時候數值不一樣,此處爲了說明 MC\MU並不是jdk的環境變量配置的MetaspaceSize 。並且使用jstat -gcutil執行出來的結果M 的百分比並不代表觸發 FullGC的閾值~
後來通過網上找到說jdk的環境變量的配置-XX:MetaspaceSize=128m 這纔是觸發元空間FullGC的條件,對比了下線上分配百分比,所以先找到運維把預發環境的環境變量-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m部分 都配置成256m(至於爲啥是256,明天可以根環境據修改後的壓測分時數據再做下說明),按照原來的並變量發數再壓一次, 果然沒有再出現堆使用率很低並且還在不配置停FullGC的現象。