前言
JVM 的参数有好几百个, 听着有点吓人, 好在最常用的参数只有两个, 其他绝大多数参数都无需调整. 可以参考廖雪峰的文章: JVM 调优的正确姿势
-Xms8g -Xmx8g
Oracle 对 JVM 参数的说明文档
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 内存模型
图片来源于网络
常用参数
-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 阈值
下面测试的粒度为 GB, 也可以到 MB
以下命令适用于 JDK7/JDK8
- # 测试环境
- Windows 10
- JDK7
- # CompressedOops 阈值
- # 32 G,false 表示超过了阈值
- > java -Xmx32g -XX:+PrintFlagsFinal 2> nul | findstr UseCompressedOops
- bool UseCompressedOops = false {lp64_product}
- # 31G,true 表示在阈值之内
- > java -Xmx31g -XX:+PrintFlagsFinal 2> nul | findstr UseCompressedOops
- bool UseCompressedOops := true {lp64_product}
- # zero based Compressed Oops 阈值
- # 32G, 未启用压缩
- > java -server -Xms32G -Xmx32G -XX:+UseConcMarkSweepGC -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompressedOopsMode -version
- java version "1.7.0_21"
- Java(TM) SE Runtime Environment (build 1.7.0_21-b11)
- Java HotSpot(TM) 64-Bit Server VM (build 23.21-b01, mixed mode)
- # zero based Compressed Oops 阈值
- # 30G,Non-zero
- > java -server -Xms30G -Xmx30G -XX:+UseConcMarkSweepGC -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompressedOopsMode -version
- Protected page at the reserved heap base: 0x000000007fff0000 / 65536 bytes
- heap address: 0x0000000080000000, size: 30802 MB, Compressed Oops with base: 0x000000007ffff000
- java version "1.7.0_21"
- Java(TM) SE Runtime Environment (build 1.7.0_21-b11)
- Java HotSpot(TM) 64-Bit Server VM (build 23.21-b01, mixed mode)
- # 30G,Zero based
- > java -server -Xms29G -Xmx29G -XX:+UseConcMarkSweepGC -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompressedOopsMode -version
- heap address: 0x00000000bae00000, size: 29778 MB, zero based Compressed Oops
- java version "1.7.0_21"
- Java(TM) SE Runtime Environment (build 1.7.0_21-b11)
- Java HotSpot(TM) 64-Bit Server VM (build 23.21-b01, mixed mode)
测试案例
Why 35GB Heap is Less Than 32GB - Java JVM Memory Oddities
这个案例中, 分配 32g 比 31g 能创建的对象少了 50%
587889429/385481085 ≈ 1.525
Going over Xmx32G heap boundary means you will have Less memory available http://java-performance.info/over-32g-heap-java/
这个案例中, 48g 才基本达到 31g 的效果
来源: https://segmentfault.com/a/1190000022603726