JVM调优通用知识
背景和价值
1. 垃圾回收器选择
- 单核CPU 选择 Serial 垃圾回收器
- 多核CPU,4G内存建议CMS
- 8G或者以上物理内存,在G1(JDK8以上)和ZGC (JDK15或者以上)之间做选择。
核心选型维度对比
| 维度 | G1 GC | ZGC |
|---|---|---|
| 目标停顿时间 | 50~200ms(可预测) | <1ms(亚毫秒级) |
| 吞吐量 | 中高(适合通用型应用) | 中等(牺牲部分吞吐换延迟) |
| 内存开销 | 堆的5%~10%(维护RSet等结构) | 堆的15%~20%(染色指针、元数据) |
| 适用堆大小 | 4GB~64GB(最佳区间) | ≥16GB(优势随堆增大而提升) |
| 适用场景 | Web服务、企业应用、批处理 | 实时交易、游戏服务器、云原生 |
2. 堆内存设置多大
(1) 中小规模内存(4GB–64GB)
物理内存配置:
堆内存(-Xmx)建议设为物理内存的50%~60%,例如:
物理内存8GB → 堆内存4GB–5GB
物理内存16GB → 堆内存8GB–10GB
(2) 大规模内存(64GB–2TB)
适用场景:大数据处理、实时分析等。
物理内存配置:
堆内存可占物理内存的70%~80%,例如:
最佳实践 8G容器5G堆
JVM进程占用的内存:heap+metaspace+ 额外的几百M(代码多的程序,甚至上G的空间),所以8G物理内存,分配5G最大堆内存比较合适
案例:生产环境8G内存,JDK为1.8,最大堆设置6G,元数据空间设置为256M。 生产运行一段时间,运维监控发现物理内存用到90%!!
通过top查看,JAVA进程占7G内存,远大于6G+256M+线程栈的几十M的内存。 那么多出的700M内存花到哪里呢?
通过arthas dashboard分析
Memory used total max usage GC
heap 2210M 6092M 6092M 36.28% gc.parnew.count 2078
par_eden_space 204M 409M 409M 49.83% gc.parnew.time(ms) 115760
par_survivor_space 3M 51M 51M 7.28% gc.concurrentmarksweep.count 24
cms_old_gen 2002M 5632M 5632M 35.56% gc.concurrentmarksweep.time(ms) 101565
nonheap 287M 299M -1 95.96%
code_cache 100M 101M 240M 41.77%
metaspace 167M 177M -1 94.57%
- JVM本身需要的内存,包括其加载的第三方库以及这些库分配的内存。内存映射文件,包括JVM加载的一些JAR和第三方库,以及程序内部用到的。上面 pmap 输出的内容里,有一些静态文件所占用的大小不在Java的heap里
- NIO的DirectBuffer是分配的native memory
- Native Memory包含Native Code,Native Stack。对应arthas的nonheap+code_cache。JIT(Just-In-Time (JIT) 编译器是运行时环境的一个组件,通过在运行时将字节码编译为本机机器代码来提高Java™ 应用程序的性能),JVM会将Class编译成native代码,这些内存也不会少,如果使用了Spring的AOP,CGLIB会生成更多的类,JIT的内存开销也会随之变大。一些JNI接口调用的native库也会分配一些内存,如果遇到JNI库的内存泄露,可以使用valgrind等内存泄露工具来检测
- 线程栈,每个线程都会有自己的栈空间,如果线程一多,这个的开销就很明显
- Metaspace:class文件元信息描述,编译后的代码数据,引用类型数据,类文件常量池(而字符串常量池 存在于堆中)
总结
JVM进程占用的内存:heap+metaspace+ 额外的几百M(代码多的程序,甚至上G的空间),所以8G物理内存,分配5G最大堆内存比较合适
什么是运行时常量池
运行时常量池
运行时常量池就是将编译后的类信息放入方法区中,也就是说它是方法区的一部分。
运行时常量池用来动态获取类信息,包括:class文件元信息描述、编译后的代码数据、引用类型数据、类文件常量池等。
运行时常量池是在类加载完成之后,将每个class常量池中的符号引用值转存到运行时常量池中。每个class都有一个运行时常量池,类在解析之后将符号引用替换成直接引用,与全局常量池中的引用值保持一致。
3. 其他通用调优考虑
-Xms 和 -Xmx` 设置为相同的值,以避免堆内存动态调整带来的性能开销。
设置 Survivor 区比例。如果应用有大量短期对象,可以适当增加 Survivor 区的大小。
参考资料
https://blog.csdn.net/guyue35/article/details/124416121
arthas dashboard命令
https://zhuanlan.zhihu.com/p/383283993

浙公网安备 33010602011771号