JVM 引數調優(qbit)

qbit發表於2020-05-11

前言

  • JVM 的引數有好幾百個,聽著有點嚇人,好在最常用的引數只有兩個,其他絕大多數引數都無需調整。可以參考廖雪峰的文章: JVM調優的正確姿勢
-Xms8g 
-Xmx8g

Client/Server

  • JVM 有兩種執行模式 Server 與 Client。
  • Client 模式啟動速度較快,Server 模式啟動較慢。
  • 啟動進入穩定期長期執行之後 Server 模式的程式執行速度比 Client 要快很多。
  • 檢視當前虛擬機器處於哪種模式
λ java -version
java version "1.8.0_162"
Java(TM) SE Runtime Environment (build 1.8.0_162-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.162-b12, mixed mode)
  • 64 位 JDK 無法切換到 Clinet 模式

列印 JVM 引數

  • 列印 JVM 引數初始值
λ java -XX:+PrintFlagsInitial
  • 列印 JVM 引數最終值
λ java -XX:+PrintFlagsFinal 2> nul
  • 列印被修改過的 JVM 引數
# 輸出經由人工換行
λ java -XX:+PrintCommandLineFlags 2> nul
-XX:InitialHeapSize=266579392 
-XX:MaxHeapSize=4265270272 
-XX:+PrintCommandLineFlags 
-XX:+UseCompressedClassPointers 
-XX:+UseCompressedOops 
-XX:-UseLargePagesIndividualAllocation 
-XX:+UseParallelGC

jvm 記憶體模型

  • 圖片來源於網路

image.png

常用引數

-Xms: 初始堆大小
-Xmx: 最大堆大小
-XX:NewSize: 年輕代初始化記憶體的大小(注意:該值需要小於-Xms的值)
-XX:MaxnewSize: 年輕代可被分配的記憶體的最大上限(注意:該值需要小於-Xmx的值)
    從 JKD1.4 開始,MaxnewSize 是通過 NewRatio 計算出來的
-Xmn: 對-XX:newSize、-XX:MaxnewSize兩個引數同時進行配置(JDK1.4之後才有該引數)
    官方推薦為對大小的 3/8,即 1/4 到 1/3 之間
-XX:NewRatio: 設定老年代和年輕代的比值
   若 -Xmn 已指定,則 OldSize = HeapSize - NewSize,無需再按比例計算。
   例如 NewRatio 為 3,表示 老年代/年輕代 = 3,年輕代佔整個堆記憶體大小的 1/4
  • 對於年輕代的堆記憶體大小,預設情況下是通過 NewRatio(2) 計算出來的,即佔用 1/3;在配置 Xmn 後,會覆蓋預設的通過 NewRatio 計算出來的年輕代堆大小值
# 摘錄的部分的輸出行
# MaxHeapSize/MaxNewSize = 4265607168/1421869056 = 3
λ java -XX:+PrintFlagsFinal
    uintx NewRatio = 2                   {product}
    uintx MaxNewSize    := 1421869056    {product}
    uintx MaxHeapSize   := 4265607168    {product}
  • 一般 -Xms、-Xmx 兩個引數會配置相同的值(優點:能夠在Java垃圾回收機制清理完堆區後不需要重新分隔計算堆區的大小而浪費資源)。

CompressedOops

壓縮普通物件指標

compressed ordinary object pointers,壓縮普通物件指標
(0, 2GB]      Compressed Oops mode: 32-bit
[2GB, 26GB]   Compressed Oops mode: Zero based,26G不是確切值,視系統而定
(26GB, 32GB)  Compressed Oops mode: Non-zero disjoint base,32G不是確切值,視系統而定
[32GB, )      CompressedOops 失效,32G不是確切值,視系統而定

CompressedOops

檢查 CompressedOops 閾值

  • 下面測試的粒度為 GB,也可以到 MB
# CompressedOops 閾值
# 32 G,false 表示超過了閾值
$ ./jdk/bin/java -Xmx32g -XX:+PrintFlagsFinal 2> /dev/null | grep UseCompressedOops
    bool UseCompressedOops    = false    {lp64_product}
# 31G,true 表示在閾值之內
$ ./jdk/bin/java -Xmx31g -XX:+PrintFlagsFinal 2> /dev/null | grep UseCompressedOops
    bool UseCompressedOops    := true    {lp64_product}
# zero based Compressed Oops 閾值
# 31G,Non-zero
./jdk/bin/java  -server -Xms31G -Xmx31G -XX:+UnlockDiagnosticVMOptions -Xlog:gc+heap+coops=info -version
[0.134s][info][gc,heap,coops] Heap address: 0x0000001000800000, size: 31744 MB, Compressed Oops mode: Non-zero disjoint base: 0x0000001000000000, Oop shift amount: 3
openjdk 13.0.2 2020-01-14
OpenJDK Runtime Environment AdoptOpenJDK (build 13.0.2+8)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 13.0.2+8, mixed mode, sharing)
# 30G,Zero based
./jdk/bin/java  -server -Xms30G -Xmx30G -XX:+UnlockDiagnosticVMOptions -Xlog:gc+heap+coops=info -version
[0.128s][info][gc,heap,coops] Heap address: 0x0000000080000000, size: 30720 MB, Compressed Oops mode: Zero based, Oop shift amount: 3
openjdk version "13.0.1" 2019-10-15
OpenJDK Runtime Environment AdoptOpenJDK (build 13.0.1+9)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 13.0.1+9, mixed mode, sharing)

測試案例

這個案例中,分配 32g 比 31g 能建立的物件少了 50%
587889429/385481085 ≈ 1.525

35GB小於32GB

這個案例中,48g 才基本達到 31g 的效果

48GB=31GB

本文出自 qbit snap

相關文章