JVM 命令

  • 通过 jps 或者 ps 获取进程号
  • 通过 jinfo 获取 jvm 环境参数
  • 通过 jstat 查询 jvm 当前 gc 情况
    • jstat -gc 获取 gc 情况
      • jstat-gccause 额外输出上次 GC 原因
  • 通过 jmap 获取 jvm 运行时内存情况
    • 通过 jmap -dump 获取 jvm dump 文件分析 jvm 内存占用情况,线上环境谨慎使用存在系统宕机风险
  • 通过 jstack 获取 jvm 中当前所有线程的运行情况和线程当前状态。分析是否死锁
    • 查看当前 java stack 和 native stack 的信息

JVM 调优

对参数设置、Java 命令的学习,都是为了 JVM 调优王在调优之前,我们需要记住下面的原则:

多数的 Java 应用不需要在服务器上进行 GC 优化,基本是在代码业务上的优化
多数导致 GC 问题的 Java 应用,都不是因为我们参数设置错误,而是代码问题(如 static 对象太多等)
在应用。上线之前,先考虑将机器的 JVM 参数设置到最优(最适合)
减少创建对象的数量
减少使用全局变量和大对象
GC 优化是到最后不得已才采用的手段
在实际使用中,分析 GC 情况优化代码比优化 GC 参数要多得多
GC 优化的目的:
将转移到老年代的对象数量降低到最小
减少 full GC 的执行时间

(一) 调优步骤
真正熟练的使用 GC 调优,是建立在多次进行 GC 监控和调优的实战经验上的,进行监控和调优的一般步骤为:

监控 GC 的状态。
使用各种 JVM 工具,Java 命令等,查看当前日志,分析当前 JVM 参数设置,并且分析当前堆内存快照和 gc 日志,根据实际的各区域内存划分和 GC 执行时间,觉得是否进行优化
分析结果,判断是否需要优化
如果各项参数设置合理,系统没有超时日志出现,GC 频率不高,GC 耗时不高,那么没有必要进行 GC 优化;如果 GC 时间超过 1-3 秒,或者频繁 GC,则必须优化
注:如果满足下面的指标,则一般不需要进行 GC:
Minor GC 执行时间不到 50ms
Minor GC 执行不频繁,约 10 秒一次
Full GC 执行时间不到 1s
Full GC 执行频率不算频繁,不低于 10 分钟 1 次
调整 GC 类型和内存分配
如果内存分配过大或过小,或者采用的 GC 收集器比较慢,则应该优先调整这些参数,并且先找 1 台或几台机器进行 beta, 然后比较优化过的机器和没有优化的机器的性能对比,并有针对性的做出最后选择
不断的分析和调整 通过不断的试验和试错,分析并找到最合适的参数
全面应用参数 如果找到了最合适的参数,则将这些参数应用到所有服务器,并进行后续跟踪
(二) 常见问题
频繁 GC 问题或内存溢出问题
(1)使用 jps 查看线程 ID
(2)使用 jstat -gc 3331 (ID) 250 20 查看 gc 情况,一般比较关注 PERM 区的情况,查看 GC 的增长情况
(3)使用 jstat -gccause: 额外输出上次 GC 原因
(4)使用 jmap -dump:format=b,file=heapDump 3331 生成堆转储文件
(5)使用 jhat 或者可视化工具 (Eclipse Memory Analyzer、IBM HeapAnalyzer) 分析堆情况
(6)结合代码解决内存溢出或泄露问题
死锁问题
使用 jps 查看线程 ID
使用 jstack 3331: 查看线程情况
(1)首先需要确定 java 进程是否发生死锁
(2)打开 jvisualvm 工具,专门分析 JVM
CPU,内存使用情况,以及线程的运行信息查看当前 java 进程各个线程运行的状态 (颜色)
(3)通过 jvisualvm 的线程 dump 或者 jstack 命令把当前 java 进程所有线程的调用堆栈信息打印出来
(4)分析 main 线程和子线程有没有关键短语: waitingfor (资源地址) 4 waiting to lock (资源地址) 4
(5)看线程函数调用栈,定位到源码上,具体问题具体分析