0%

Java-Jvm-Optimization

jvm调优是日常工作中经常会使用的技巧,整理下。

JVM调优

为什么要调优,当默认配置参数不能很好的发挥程序性能的时候。

  • Heap内存(老年代)持续上涨达到设置的最大内存值。
  • Full GC 次数频繁。
  • GC 停顿时间过长(超过1秒)。
  • 应用出现OutOfMemory 等内存异常。
  • 应用中有使用本地缓存且占用大量内存空间。
  • 系统吞吐量与响应性能不高或下降。

常用方式

  • 上线之前,应先考虑将机器的JVM参数设置到最优。(启动参数)
  • 大多数导致GC问题的原因是代码层面的问题导致的(代码层面)。
  • 减少创建对象的数量(代码层面)。
  • 减少使用全局变量和大对象(代码层面)。
  • 优先架构调优和代码调优,JVM优化是不得已的手段(代码、架构层面)。
  • 分析GC情况优化代码比优化JVM参数更好(代码层面)。

启动参数

调优的最终目的都是为了令应用程序使用最小的硬件消耗来承载更大的吞吐。jvm调优主要是针对垃圾收集器的收集性能优化,令运行在虚拟机上的应用能够使用更少的内存以及延迟获取更大的吞吐量。

  • 延迟:GC低停顿和GC低频率。
  • 低内存占用。
  • 高吞吐量。
  • 堆内存 = Old + Eden + S0 + S1
  • 年轻的 = Eden(新生代) + S0 + S1
  • 标准参数(-),所有JVM都必须支持这些参数的功能,而且向后兼容
  • 非标准参数(-X),默认JVM实现这些参数的功能,但是并不保证所有JVM实现都满足,且不保证向后兼容。
  • 非稳定参数(-XX),此类参数各个JVM实现会有所不同,将来可能会不被支持,需要慎重使用。
  • Heap 内存使用率 <= 70%;
  • Old generation内存使用率<= 70%;
  • avgpause <= 1秒;
  • Full gc 次数0 或 avg pause interval >= 24小时 ;
1
-XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=128m -Xms1024m -Xmx1024m -Xmn256m -Xss256k -XX:SurvivorRatio=8 -XX:+UseConcMarkSweepGC
  • 简单介绍下参数
1
2
3
4
5
6
7
8
9
-XX:MetaspaceSize=128m (元空间默认大小)
-XX:MaxMetaspaceSize=128m (元空间最大大小)
-Xms1024m (堆最大大小)
-Xmx1024m (堆默认大小)
-Xmn256m (新生代大小)
-Xss256k (棧最大深度大小)
-XX:SurvivorRatio=8 (新生代分区比例 8:2)
-XX:+UseConcMarkSweepGC (指定使用的垃圾收集器,这里使用CMS收集器)
-XX:+PrintGCDetails (打印详细的GC日志)
  • 虽然有了介绍但是依然不清楚具体是干啥的。并且Java虚拟机提供了非常多的参数命令。下面代码可以输出支持的参数数量
1
2
3
4
5
java -XX:+PrintFlagsFinal -XX:+UnlockDiagnosticVMOptions -version | wc -l
openjdk version "1.8.0_275"
OpenJDK Runtime Environment (AdoptOpenJDK)(build 1.8.0_275-b01)
OpenJDK 64-Bit Server VM (AdoptOpenJDK)(build 25.275-b01, mixed mode)
838
  • 堆内存大小配置

建议 -Xms = 最大内存 * [0.6. ~0.8] 这里需要考虑系统损耗内存、和实际物理内存。

  • 堆内存与堆外内存

    • 堆内存

    必须是1024的倍数,且不能低于2M。

    32位机器,最大1G/4G 64位机器最大可以超过 32G/64G

    • 堆外内存

    堆外内存一般指 Direct Memory ,不受GC控制,JVM、Netty都可能使用堆外内存。

1
-XX:MaxDirectMemorySize 限制
如何理解这些参数的含义?

首先我们需要理解java是如何运行的,为什么需要java虚拟机?

我们常用方式一般是安装java运行环境(jre)用命令行的方式启动或者直接双击jar运行。jre包含的java运行的必要环境。

Java 作为一门高级程序语言,它的语法非常复杂,抽象程度也很高。编译出来的也不是机器可以直接直接运行代码。所以使用面向Java语言的虚拟机运行Java编译以后的特定代码。这里的特定代码指的是Java字节指令码。

JVM 内存分配性能问题
  • 在应用服务的特定场景下,JVM 内存分配不合理带来的性能表现并不会像内存溢出问题这么突出。如果没有深入到各项性能指标中去,是很难发现其中隐藏的性能损耗。
  • JVM 内存分配不合理最直接的表现就是频繁的 GC,这会导致上下文切换等性能问题,从而降低系统的吞吐量、增加系统的响应时间。

分析 GC 日志

  • 在进行压测的时候,我们需要对GC日志进行分析。
1
-XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:/log/heap.log
  • -XX:PrintGCTimeStamps:打印 GC 具体时间;
  • -XX:PrintGCDetails :打印出 GC 详细日志;
  • -Xloggc: path:GC 日志生成路径。
  • JVM 内存调优通常和 GC 调优是互补的,基于以上调优,可以对年轻代和堆内存的垃圾回收算法进行调优。