Java JVM 优化指南:从 Java 8 到 Java 21
同事最近遇到一次OOM,导出内存镜像后发现很小,说明内存分配的少了,Docker容器分配了4G内存,内存占用这么少,很显然是没有基本的JVM配置导致的,本文针对 Java8 到 Java 21 给出一个基础的配置,首先保证能合理的使用内存。
本文针对4G内存进行配置,分配3/4的内存给JVM使用,留1/4给堆外内存以及操作系统使用。如果你分配了不同的内存大小,按照类似比例计算即可。
0. 为什么需要配置 JVM?
我们需要先了JVM运行时堆的默认值:
- 初始堆(
Xms
)大小为物理内存的 1/64 - 最大堆(
Xmx
)大小为物理内存的 1/4
当给容器分配4G内存时,默认最多使用1G,大部分内存都被浪费了,所以我们必须合理配置才能充分利用内存。
1. 针对4G Java 8环境推荐的JVM参数配置
对于在4G内存环境中运行的Java 8应用程序,以下是推荐的JVM参数配置:
1 |
|
2. 推荐JVM参数的介绍
让我们逐一解释这些参数:
-Xms3072m -Xmx3072m
: 设置初始堆大小和最大堆大小为3GB。这是4GB总内存的75%,为系统和本地内存留出足够空间。-XX:+UseG1GC
: 使用G1垃圾收集器,它在大多数场景下都表现良好。-XX:MaxGCPauseMillis=200
: 设置目标最大GC暂停时间为200毫秒,平衡吞吐量和延迟。-XX:G1HeapRegionSize=8M
: 设置G1区域大小为8MB,适合大多数应用。-XX:InitiatingHeapOccupancyPercent=45
: 当堆使用率达到45%时开始并发GC周期,提供良好的缓冲。-XX:+HeapDumpOnOutOfMemoryError
: 在发生OOM错误时自动生成堆转储,有助于问题诊断。-XX:HeapDumpPath=/path/to/heapdump.hprof
: 指定堆转储文件的保存路径。-XX:MaxRAMPercentage=75.0
: 限制JVM最多使用系统内存的75%。
这种配置旨在优化内存使用,提高GC效率,同时为诊断潜在问题提供支持。
注意
-XX:HeapDumpPath=/path/to/heapdump.hprof
参数需要修改路径。容器环境(含K8S)使用时可以考虑指定到挂载的存储路径,避免容器自动重启丢失。
3. 如何应用JVM参数
使用上面的JVM参数替代下文中的
[JVM参数]
部分。
物理机环境
在命令行中直接启动Java应用时使用:
1 |
|
Docker环境
在Dockerfile中设置:
1 |
|
Docker Compose环境
在 docker-compose.yml 文件中设置:
1 |
|
Kubernetes环境
在部署配置文件中设置:
1 |
|
4. 针对低版本Java 8的额外配置
对于Java 8u191之前的版本,需要添加以下参数来启用容器感知:
1 |
|
同时,将-XX:MaxRAMPercentage=75.0
替换为-XX:MaxRAMFraction=1
。
5. 针对Java 11的调整
Java 11默认启用了容器感知,因此可以移除容器相关的特殊参数。主要调整如下:
- 移除
-XX:+UnlockExperimentalVMOptions
和-XX:+UseCGroupMemoryLimitForHeap
- 保留
-XX:MaxRAMPercentage=75.0
- 考虑添加
-XX:+UseContainerSupport
(虽然默认已启用)
6. 针对Java 17的调整
Java 17进一步改进了GC和性能。建议的调整包括:
- 考虑使用ZGC:
-XX:+UseZGC
- 如果使用G1GC,可以尝试
-XX:G1PeriodicGCInterval=0
来禁用周期性GC - 添加
-XX:+UseStringDeduplication
以减少内存使用
7. 针对Java 21的调整
Java 21引入了更多优化和新特性。建议的调整包括:
- 使用新的Generational ZGC:
-XX:+UseZGC -XX:+ZGenerational
- 启用预览特性:
--enable-preview
- 考虑使用虚拟线程:
-Djdk.virtualThreadScheduler.parallelism=<number of cores>
- 如果使用G1GC,可以尝试
-XX:G1PeriodicGCSystemLoadThreshold=<threshold>
来基于系统负载触发周期性GC
记住,这些是建议的起点。实际配置应该根据您的具体应用程序需求和性能测试结果进行微调。始终在生产环境使用前进行彻底的测试和评估。
欢迎大家提出自己的见解和经验,帮助更多的Java开发者优化他们的JVM配置。