有一定 Java 工作经验的朋友不可避免地会遇到或处理 OOM 和 GC 问题。OOM 和 GC 问题也是面试时面试官经常问的问题。分享多年积累的一些小经验,共同进步。
0x01:未雨绸缪无论是部署到生产环境中的应用, C/S 结构,还是 B/S 结构应用服务。必须基于 Shell 脚本编写的启动脚本。C/S 结构应用服务 Shell 脚本一般由公司内部开发人员编写;以下一个 C/S 简单启动脚本的结构应用服务。
java -Xms1024m -Xmx1024m -XX:PermSize=256m \-XX:MaxPermSize=512m -XX:-HeapDumpOnOutOfMemoryError \-XX:HeapDumpPath=./ -XX:+PrintGCDetails -Xloggc:./gc.log -jar \plugins/org.eclipse.equinox.launcher_1.0.201.R35x_v20090715.jar -clean -refresh &
而 B/S 应用服务器的启动通常是结构 Shell 脚本。例如,应用服务器 Apache Tomcat bin 目录下的 startup.sh。
而 Apache Tomcat 的启动 Shell 脚本没有配置 OOM 时,打印 JVM JVM参数和内存快照的打印 GC 日志的JVM参数。因此,生成环境 Tomcat 一般需要提供服务 JVM 参数优化。
如何在线 OOM 和 GC 未雨绸缪?也就是说,我认为我部署的任何服务都会发生 OOM 和 GC 问题。在启动脚本中添加相应的参数,以防止真正发生 OOM 和 GC 问题时,无证可查。
打印 OOM 快照配置:
- -XX:-HeapDumpOnOutOfMemoryError :当堆内存空间溢出时,输出堆内存快照
- -XX:HeapDumpPath :指定输入目录
也就是说,当它发生时 OutOfMemoryError 只有在错误的时候才能触发 -XX:HeapDumpOnOutOfMemoryError 输出到 -XX:HeapDumpPath 指定目录。
打印 GC 日志:
- -XX:+PrintGCDetails:打印 GC 详细的日志信息
- -Xloggc:GC 输入日志的目录
有时候不一定要停机才能分析 OOM 和 GC 问题。目前,大型系统服务都配备了监控系统,一旦发现服务运行不健康,就会引发预警。将邮件、短信等发送给运维人员,此时就可以对触发预警的服务进行分析。此时,分析这些提供生成服务的应用服务需要特别小心,造成更严重的生产事故,给公司带来严重损失,但也给自己的评估带来不利影响。
一般用于向上分析 JDK 提供各种操作和维护工具,找出问题所在。
- 监视工具:jps、jstat、jstatd、jmc
- 故障排除工具:jcmd、jinfo、jhat、jmap、jsadebugd、jstack
官网:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/
jps (JavaVirtual Machine Process Status Tool): 虚拟机工艺状态工具
命令格式:jps [options] [hostid]
-q : 只生成本地JVM标识符列表,以抑制类名的输出、JAR文件名和传递给main方法的参数。
-m: 显示传递给main方法的参数。输出可能是null嵌入式JVM。
-l : JAR文件的完整路径名显示应用程序main类的完整包名或应用程序的完整路径名。
-v : 显示传输给JVM的参数。
-V : 只生成本地JVM标识符的列表,以抑制类名的输出、JAR文件名和传递给main方法的参数。
-Joption : 将option传递给JVM,其中选项是optionsJava应用程序启动器参考页面中描述的选项之一。
例如,-J-Xms48m将启动内存设置为48 MB。
- jstat (Java Virtual Machine (JVM) statistics):监控Java虚拟机(JVM)统计信息
命令格式:jstat [ option vmid [interval[s|ms] [count] ]
Interval: 间隔时间 count:次数
class:显示加载器行为的统计信息。
compiler:Java显示 HotSpot VM即时编译器行为的统计信息。
gc:显示垃圾回收堆行为的统计信息。
gccapacity:统计数据显示了世代及其相应的空间容量。
gccause:显示垃圾回收统计信息(相同)-gcutil)摘要包括垃圾收集事件的最终原因和当前(适用时)。
gcnew:显示新一代行为的统计信息。
gcnewcapacity:显示新一代及其相应空间大小的统计信息。
gcold:统计信息显示旧版本和Metaspace统计信息。
gcoldcapacity:显示旧一代大小的统计信息。
gcmetacapacity:显示元空间大小的统计信息。
gcutil:摘要显示垃圾收集统计信息。
printcompilation:Java显示 HotSpot VM编译方法统计信息。
- jinfo (Configuration Info for Java):生成配置信息
命令格式:jinfo [ option ] pid
-flag 名称 : 打印指定命令行标志的名称和值。
-flag [+ | - ]名称 : 启用或禁用指定的布尔命令行标志。
-flag name = value : 将指定的命令行标志设置为指定的值。
-flags : 将命令行标志打印到JVM。
-sysprops : 以打印Java系统属性为名。
- jmap (Memory Map for Java):内存映射工具 [ 生成堆转储快照 ]
命令格式:jinfo [ option ] vmid
-dump:[live,] format = b,file = filename :Java堆filename以hprof二进制格式转储。live子选项说明dump是否存活。
-finalizerinfo : 打印正在等待最终确定对象的信息(linux)。
-heap :显示java堆的详细信息,如使用哪种回收器、参数配置、分代等(linux)。
-histo [:live] : 显示堆中对象的统计信息,包括类别、实例数量和总容量。
-clstats : 打印Java堆类加载器的智能统计数据。对于每个类加载器,其名称、活动程度、地址、父加载器及其类别的数量和大小。
-F : -dump或 -当histo选项不响应时,该选项强制生成dump快照(不支持live)。
- jhat (JVM Heap Analysis Tool):虚拟机堆储快照分析工具
命令格式:jhat [ options ] 堆转储文件
- jstack (Stack Trace for Java):Java堆栈跟踪工具
命令格式:jstack [ options ] pid
-F : jstack[ -l] 当pid不响应时,强制堆栈转储。
-l : 打印其他关于锁的信息,例如,java.util.concurrent 同步器列表。
-m : 打印混合堆栈跟踪模式,包括 Java 和本机 C/C ++ 框架。
在众多的监测工具和故障排除工具中,常用的是 jps、jstat、jstack 和 jmap
0x03:线下分析如果肉眼看不到一些问题的端倪,就不能通过未雨绸缪和线上分析来影响生产。这两个步骤需要收集。 JVM 内存快照,线下分析。JDK 以及一些第三方工具,提供了一个非常有用的可视化工具来分析JVM 内存快照。主要有 JDK 提供的 jconsole、VisualVM;Eclipsee由第三方提供 Memory Analyzer(免费)、JProfiler(商业)。常用的化学工具可以参考本文 [ Java内存泄漏 GC 常用易用的工具有哪些? ]