学习JVM调优前必备的知识

156 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情

1 JVM常用命令行参数

1.1 HotSpot参数分类

  • 标准:-开头,所有的HotSpot都支持
  • 非标准:-X开头,特定版本HotSpot支持特定命令
  • 不稳定:-XX开头,下个版本可能取消

1.2 一些常用命令

  1. java -XX:+PrintCommandLineFlags HelloGC
    • 查看程序默认使用的JVM参数
  2. java -Xmn10M -Xms40M -Xmx60M -XX:+PrintCommandLineFlags -XX:+PrintGC HelloGC
    • -Xms40M最小堆大小,
    • -Xmx60M最大堆大小,最大和最小一般设置为一样的,
    • -Xmn10M新生代大小
    • +PrintGC打印GC回收信息
      • PrintGCDetails 打印详细的GC信息
      • PrintGCTimeStamps 打印GC产生的时候的时间
      • PrintGCCauses 打印GC产生的原因
  3. java -XX:+UseConcMarkSweepGC -XX:+PrintCommandLineFlags HelloGC
    • 使用CMS垃圾回收器
  4. java -XX:+PrintFlagsInitial
    • 查看所有JVM参数启动的初始值
  5. java -XX:+PrintFlagsFinal
    • 所有JVM参数的最终值
  6. java -XX:+PrintFlagsFinal | grep xxx
    • 在结果集中找到对应的参数
  7. java -XX:+PrintFlagsFinal -version |grep GC

2 GC日志分析

[GC (Allocation Failure) [ParNew: 6144K->640K(6144K), 0.0265885 secs] 
6585K->2770K(19840K), 0.0268035 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]
  • GC:YGC,若是FullGC的话会写FullGC
  • (Allocation Failure):GC产生的原因
  • ParNew:产生的代,年轻代
  • 6144K->640K:回收前年轻代空间大小,回收后年轻代空间大小
  • (6144K):整个年轻代总的大小
  • 0.0265885 secs:这次垃圾回收用的时间
  • 6585K->2770K(19840K):回收前堆的大小,回收后堆的大小,整个堆的大小
  • 0.0268035 secs:所用时间

3 调优前的基本概念

  1. 吞吐量:用户代码时间 /(用户代码执行时间 + 垃圾回收时间)
  2. 响应时间:STW越短,响应时间越好 所谓调优,首先确定,是在追求啥?吞吐量优先,还是响应时间优先?
  • 吞吐量优先的话: 场景一般为科学计算,数据挖掘等请求发出之后业务运行很久的场景,不要求即时返回。 一般使用 PS+PO
  • 响应时间优先的话:一般为网站,对外提供的API等服务 一般使用G1

4 什么是调优?

  1. 根据需求进行JVM规划和预调优
  2. 优化运行JVM运行环境
  3. 解决JVM运行过程中出现的各种问题(OOM并不是调优的全部)

5 调优步骤

  1. 熟悉业务场景(没有最好的垃圾回收器,只有最合适的垃圾回收器)
    1. 查看响应时间、停顿时间
    2. 查看吞吐量 = 用户时间 /( 用户时间 + GC时间) [PS]
  2. 选择回收器组合
  3. 计算内存需求
  4. 选定CPU(越高越好)
  5. 设定年代大小、升级年龄
  6. 设定日志参数
  7. 观察日志情况

6 几个常见的垃圾回收器

6.1 Serial

单线程垃圾处理器,运行时会发生STW(Stop The World),也就是阻塞线程,然后进行垃圾回收,再释放线程。
当内存特别大的时候,STW时间会很长,现在使用的极少。
也就适用几十兆的内存

6.2 Serial Old

也是单线程,是Serial在老年代的算法,现在基本不用
也就适用几十兆的内存

6.3 Parallel Scavenge

当没有进行任何设置和调优的时候,年轻代默认使用此垃圾处理器
也会发生STW,但是是多线程回收垃圾
一般适用上百兆到几个G的内存

6.4 parallel old

当没有进行任何设置和调优的时候,老年代默认使用此垃圾处理器
也会发生STW,但是是多线程回收垃圾,使用整理算法也就是标记压缩算法
一般适用上百兆到几个G的内存

6.5 ParNew

也会发生STW,然后多线程回收垃圾,默认线程数为CPU的核数
特点是有一些和CMS配合的变动

6.6 CMS

concurrent mark sweep 特点是工作线程和垃圾清除线程可以同时运行
工作时分为四步:

  1. 初始标记:进行STW,单线程标记且只标记根对象
  2. 并发标记:80%GC的时间浪费到这里,一边产生垃圾一边进行标记,多数垃圾再此时标记完成
  3. 重新标记:执行STW,多线程标记,在并发标记时产生的新的垃圾在此时标记
  4. 并发清理:清理标记的垃圾,并发清理的时候产生的垃圾叫浮动垃圾,浮动垃圾则等下一次CMS执行的时候清除

6.6.1 CMS的问题

Memory Fragmentation 内存碎片化

当内存碎片化后,已经不能装对象的时候,则Serial Old登场开始执行单线程垃圾清理,使用垃圾清除算法:Mark-Compact 标记压缩

Floating Garbage浮动垃圾

当老年代要满的时候,还有浮动垃圾清除不掉,此时Serial Old登场开始执行单线程清理垃圾,使用垃圾清除算法Mark-Compact 标记压缩
当内存特别大的时候,这两个STW的时间是无法忍受的