05-JVM虚拟机
4.JVM调优实践
4.1 JVM调优疑问三连
4.1.1 为什么JVM调优?
调优的最终目的都是为了应用程序使用最小的硬件消耗来承载更大的吞吐量。JVM调优主要是针对垃圾收集器的收集性能进行优化令运行在虚拟机上的应用,能够使用更少的内存(Footprint),及更低的延迟(Latency),获取更大的吞吐量(Throughput)。
下面展示了一些JVM调优的量化目标参考实例
调优目标:
-
堆内存使用率 <= 70%;
-
老年代内存使用率<= 70%; avg pause <= 1秒;
-
Full GC 次数0 或 avg pause interval = 24小时 ;
注意:不同应用场景的JVM调优量化目标是不一样的,这里的目标只一个参照模板。
4.1.2 什么时候JVM调优?
遇到以下情况,就需要考虑进行JVM调优:
-
系统吞吐量下降与响应延迟(P99);
-
Heap内存(老年代)持续上涨至出现OOM;
-
Full GC 次数频繁;
-
GC 停顿过长(超过1秒);
-
应用出现OutOfMemory 等内存异常;
-
应用中有使用本地缓存且占用大量内存空间;
4.1.3 调优调什么?
内存分配 + 垃圾回收!
- 合理使用堆内存
- GC高效回收占用的内存的垃圾对象
- GC高效释放掉内存空间
4.1.4 调优原则
- 优先原则:优先架构调优和代码调优,JVM优化是不得已的手段
- 大多数的Java应用不需要进行JVM优化
- 观测性原则:发现问题解决问题,没有问题不找问题
4.1.5 JVM实践调优主要步骤
第一步:监控分析GC日志
第二步:判断JVM问题:
- 如果各项参数设置合理,系统没有超时日志出现,GC频率不高,GC耗时不高,那么没有必要进行GC优化
- 如果GC时间超过1秒,或者频繁GC,则必须优化。
第三步:确定调优目标
第四步:调整参数
- 调优一般是从满足程序的内存使用需求开始,之后是时间延迟需求,最后才是吞吐量要求,要基于这个步骤来不断优化,每一个步骤都是进行下一步的基础,不可逆行之。
第五步:对比调优前后差距
第六步:重复:1、2、3、4、5步骤
- 找到最佳JVM参数设置
第七步:应用JVM参数到应用服务器:
- 找到最合适的参数,将这些参数灰度发布一部分机器,观察一段时间。
- 如果,观察结果可以验证方案的价值,则进行全量发布!
4.2 GC日志详解
4.2.1 参数配置
JVM调优典型参数设置:
-
-Xms堆内存最小值
-
-Xmx堆内存最大值
-
-Xmn新生代内存的最大值
-
-Xss每个线程的栈内存
# 计算最大线程数的公式:理论上限
Number of threads = (MaxProcess内存 - JVM内存 - ReservedOsMemory) / (ThreadStackSize)
系统最大可创建的线程数量=(机器本身可用内存 - (JVM分配的堆内存+JVM元数据区)) / Xss的值
建议:在开发测试环境可以用Xms和Xmx设置最小值最大值,但是在线上生产环境,Xms和Xmx设置的值相同防止抖动;
JVM调优设置合适大小堆内存空间,既不能太大,也不能太小。那么应该设置为多少呢?
JAVA_OPT="-Xms4096m -Xmx4096m -Xmn1024m"
JAVA_OPT="-Xms512m -Xmx512m -Xmn256m"
默认的配置是否存在性能瓶颈!
如果想要确定JVM性能问题瓶颈,需要分析GC日志
-
-XX:+PrintGCDetails 开启GC日志创建更详细的GC日志,默认关闭
-
-XX:+PrintGCTimeStamps,-XX:+PrintGCDateStamps
- 开启GC时间提示,开启时间便于我们更精确地判断几次GC操作之间的两个时间参数的区别
- 时间戳是相对于0(依据JVM启动的时间)的值,而日期戳(date stamp)是实际的日期字符串
- 由于日期戳需要进行格式化,所以它的效率可能会受轻微的影响,不过这种操作并不频繁,它造成的影响也很难被我们感知。
-
-XX:+PrintHeapAtGC 打印堆的GC日志
-
-Xloggc:./logs/gc.log 指定GC日志路径
# 配置GC日志输出
JAVA_OPT="${JAVA_OPT} -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:${BASE_DIR}/logs/gc-default.log "
4.2.2 GC日志解读
Young GC 日志含义
2021-05-18T14:31:11.340+0800: 2.340: [GC (Allocation Failure) [PSYoungGen: 896512K->41519K(1045504K)]
896512K-41543K(3435008K), 0.0931965 secs] [Times: user=0.14 sys=0.02, real=0.10 secs]
这段日志描述了一次GC(垃圾收集)事件的详细信息。让我们逐行解读每一部分的含义:
1. 第一部分:
- 时间戳和时区:2021-05-18T14:31:11.340+0800,表示事件发生的时间为2021年5月18日下午2点31分11.34秒,时区为东八区(中国标准时间)。
- 相对时间:2.340,表示该事件相对于JVM启动的时间间隔为2.34秒。
- GC类型:该行以"[GC"开始,表示这是一次Young Generation的GC。
2. 第二部分:
- 垃圾收集器名称:PSYoungGen,表示使用的是Parallel Scavenge(并行年轻代)垃圾收集器。
- 新生代内存情况:896512K->41519K(1045504K),表示在垃圾收集之前和之后,新生代的内存使用情况。在GC前,新生代使用了896512K内存,GC后剩余41519K内存(其中总共可用1045504K内存)。
- 堆内存情况:896512K-41543K(3435008K),表示在垃圾收集之前和之后,整个堆内存的使用情况。在GC前,堆内存使用了896512K,GC后剩余41543K(其中总共可用3435008K内存)。
- GC持续时间:0.0931965秒,表示这次GC的持续时间为0.0931965秒。
3. 第三部分:
- 时间统计信息:[Times: user=0.14 sys=0.02, real=0.10 secs],表示与GC相关的时间统计信息。
- user=0.14,表示GC线程消耗的CPU时间为0.14秒。
- sys=0.02,表示GC过程中操作系统调用和系统等待事件所消耗的时间为0.02秒。
- real=0.10,表示应用程序暂停的时间为0.10秒。
该日志提供了关于GC事件发生的时间、GC类型、内存使用情况以及与GC相关的时间统计信息。这些信息对于分析和调优应用程序的内存管理性能非常有用。
FullGC 日志含义
2021-05-19T14:46:07.367+0800: 1.562: [Full GC (Metadata GC Threshold)[PSYoungGen: 18640K-
>0K(1835008K)] [ParOldGen: 16K->18327K(1538048K)] 18656K->18327K(3373056K), [Metaspace: 20401K-
>20398K(1069056K)], 0.0624559 secs] [Times: user=0.19 sys=0.00,

最低0.47元/天 解锁文章
3269

被折叠的 条评论
为什么被折叠?



