生产环境 OOM 与 GC 问题的处理思路

2021-03-22 17:36:34 浏览数 (1)

有一定 Java 工作经验的朋友们,免不了要遇到过,或者处理过 OOM 和 GC 问题。OOM 和 GC 问题也是面试时,经常被面试官问题的问题。分享一下多年积累的一些小经验,共同进步。

0x01:未雨绸缪

部署到生产环境的应用,无论是 C/S 结构,还是 B/S 结构的应用服务。肯定有基于 Shell 脚本编写的启动脚本。C/S 结构的应用服务的 Shell 脚本一般是公司内部开发人员编写的;以下一个 C/S 结构应用服务的简单启动脚本。

代码语言:javascript复制
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 日志输入的目录

0x02:线上分析

有时并不一定是要宕机了才去分析 OOM 和 GC 问题。目前大型的系统服务都是配备了监控系统,一旦发现服务处于不健康运行的状态,就会触发预警。给运维人员发送邮件、短信等,这时就可以对触发预警的服务进行问题分析了。这时对这些正在提供生成服务的应用服务进行分析就需要额外小心,稍不留神就造成更严重的生产事故,给公司带来严重的损失,同时也给自己的考核带来不利影响。

对于向上分析一般使用 JDK 提供的各种运维工具,找到问题的所在。

监视工具:jps、jstat、jstatd、jmc

故障排除工具:jcmd、jinfo、jhat、jmap、jsadebugd、jstack

代码语言:javascript复制
官网:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/
  • jps (JavaVirtual Machine Process Status Tool): 虚拟机进程状况工具

命令格式:jps [options] [hostid]

-q : 抑制类名的输出,JAR文件名和传递给main方法的参数,仅生成本地JVM标识符列表。

-m: 显示传递给该main方法的参数。输出可能是null嵌入式JVM。

-l : 显示应用程序main类的完整包名或应用程序的JAR文件的完整路径名。

-v : 显示传递给JVM的参数。

-V : 抑制类名的输出,JAR文件名和传递给main方法的参数,仅生成本地JVM标识符的列表。

-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 :以hprof二进制格式转储Java堆filename。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;第三方提供的有Eclipse Memory Analyzer(免费)、JProfiler(商业)。

0 人点赞