应用假死排查过程及OutOfMemory问题定位及处理

应用假死排查过程及OutOfMemory问题定位及处理

相关关键词: java8、jmap、jstack、jstat、netstat、less 、grep、 jvm

场景

复盘一下之前遇到过的OOM问题的排查过程。业务细节暂不表,表象:应用假死,接口请求无法响应, 主要问题是业务量增加,有一个核心业务会有byte[],以及堆设置的比较小。处理过程,优化byte[]的过程,增加堆的大小。

排查过程:
1.jmap输出堆的使用情况
2.jstat输出GC信息
3.jstack 输出线程堆栈快照
4.netstat查看监听端口的TCP连接状态
5.查看日志中是否有OutOfMemory错误

jmap

jmap: java memory map 可以获取DUMP文件(堆转储快照,二进制文件);还可以获取指定java进程的内存相关信息,包括java堆各区域的使用情况,堆中对象的统计信息、类加载信息

输出当前堆各区域的是使用情况

输出当前PID应用的JVM的配置及年轻代、老年代的使用情况, 我们可以了解应用程序的内存使用情况,根据需要优化我们的 Java 应用程序。

语法: jmap -heap pid

Attaching to process ID 29296, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.232-b09

using thread-local object allocation.
Parallel GC with 8 thread(s)

Heap Configuration:
   MinHeapFreeRatio         = x
   MaxHeapFreeRatio         = x
   MaxHeapSize              = x
   NewSize                  = x
   MaxNewSize               = x
   OldSize                  = x
   NewRatio                 = x
   SurvivorRatio            = x
   MetaspaceSize            = x
   CompressedClassSpaceSize = x
   MaxMetaspaceSize         = x
   G1HeapRegionSize         = x

Heap Usage:
PS Young Generation
Eden Space:
   capacity = x
   used     = x
   free     = x
   x% used
From Space:
   capacity = x
   used     = x
   free     = x
   x% used
To Space:
   capacity = x
   used     = x
   free     = x
   x% used
PS Old Generation
   capacity = x
   used     = x
   free     = x
   x% used

x interned Strings occupying x bytes.

在Heap Configuration中各参数的含义:

MinHeapFreeRatio:堆可以被允许的最小空闲大小(以百分比表示)。
MaxHeapFreeRatio:堆中可以被允许的最大空闲空间大小(以百分比表示)。
MaxHeapSize:堆的最大尺寸。
NewSize:JVM 在创建新对象时将分配的内存区大小。
MaxNewSize:新生代的最大尺寸。
OldSize:老年代的初始大小。
NewRatio:新生代和老年代之间的比率。
SurvivorRatio:两个幸存者区域与 Eden 区域的大小比率。
MetaspaceSize:Metaspace 的初始大小(即非堆大小),用于存储加载类、方法等元数据。
CompressedClassSpaceSize:压缩类空间的大小。
MaxMetaspaceSize:Metaspace 的最大大小。
G1HeapRegionSize:G1 中的 Region 大小。每个 Region 的大小由 JVM 计算得出。

在 Heap Usage 部分,我们可以看到当前堆的使用情况,包括:

capacity:Java 堆的总容量。
used:Java 堆当前使用的总量。
free:Java 堆当前可用的数量。
42.22304174399364% used:Java 堆的当前使用率。

PS Young Generation: 年轻代
    Eden Space: eden区
    From Space: 幸存区1
    To Space: 幸存区2
PS Old Generation: 老年代

输出存活占用内存最多的10个对象按降序排序

jmap -histo:live 29296 |head -n 10

通过这个命令查看是否有不正常的对象占用太多内存导致内存泄漏

输出转储二进制文件

语法: jmap -dump:format=b,file=heap.bin

通过上面命令输出堆的转储二进制文件,通过eclipse的jconsole分析我们java程序的内存

JVM配置参数


-Xmx4048m  最大堆大小

-Xms4048m  初始堆大小

-Xmn2600m  设置年轻代的大小 建议设置为堆的3/8

-XX:+UseParallelGC  使用并行垃圾收集器,在多 CPU 系统上可以提高垃圾收集的效率。

-XX:-UseAdaptiveSizePolicy  并行收集器会自动选择年轻代区分大小和相应的Survivor区比例
 
-XX:SurvivorRatio=x   幸存区大小比率。

-XX:+HeapDumpOnOutOfMemoryError 在 OutOfMemoryError 异常发生时生成堆转储文件(heap dump)。

JVM 的配置参数可以分为以下几类:

标准参数(- 开头):这些参数主要控制 JVM 的基本行为,并且在所有的 JVM 实现中都支持。

非标准参数(-X 开头):这些参数是实现特定的,不保证所有 JVM 实现都支持,且在未来的版本中可能会有所改变。

高级参数(-XX 开头):这些参数被称为高级参数,它们提供了对 JVM 内部行为的细粒度调整,并允许用户绕过某些标准限制。这些参数也是实现特定的,并且在不同的 JVM 实现中可能有所不同。

下面是一些常用的 JVM 参数及其说明:

-Xms:初始堆大小,指定 JVM 启动时堆内存的初始大小。默认情况下,Java 虚拟机自适应地调整堆大小。

-Xmx:最大堆大小,指定 JVM 最大堆内存大小。如果堆超出该阈值,则 Java 虚拟机将抛出 OutOfMemoryError 异常。

-XX:PermSize:永久代初始值,默认值为 64 MB。

-XX:MaxPermSize:永久代最大值,默认值为 64 MB。

-XX:NewSize:新生代初始值,指定了启动时新生代的初始大小。

-XX:MaxNewSize:新生代最大值,指定了新生代的最大可用空间。

-XX:SurvivorRatio:幸存区大小比率。

-XX:+UseConcMarkSweepGC:启用 CMS 垃圾收集器,用于收集老年代内存空间的垃圾。

-XX:+UseParNewGC:启用 ParNew 垃圾收集器,用于收集新生代内存空间的垃圾。

-XX:+UseSerialGC:使用串行垃圾收集器,适用于小型应用程序和单 CPU 系统。

-XX:+UseParallelGC:使用并行垃圾收集器,在多 CPU 系统上可以提高垃圾收集的效率。

-XX:+HeapDumpOnOutOfMemoryError:在 OutOfMemoryError 异常发生时生成堆转储文件(heap dump)。

这些参数只是 JVM 参数中的一小部分,有些参数可能因版本、厂商或系统而异,使用前需要仔细查看文档或手册。

jstat

jstat: java virtual machine statistics monitoring tool

jstat -gccause pid

jstat -gccapacity pid

jstat -gc pid

options 说明
-class 显示类加载状况的信息
-compiler 显示JIT编译器的统计信息
-gc 显示垃圾回收状况的信息
-gccapacity 用于查看新生代、老年代及持久代的存储容量情况
-gccause 在-gc的基础上,显示导致GC最后一次的原因
-gcutil 显示垃圾回收的总体信息
YGC: 从应用程序启动到采样的年轻代中GC的次数
FGC: 从应用程序启动到采样是old代GC的次数
FGCT: 从应用程序启动到采样是Old代GC所用的时间(s)
GCT: 从应用程序启动到采样时GC用的总时间(s)
GCC: 当前GC原因(No GC为当前没有执行GC)
LGCC: 最后一次GC原因

jstack

jstack生成当前java应用的线程快照

输出线程快照 jstack pid > theadInfo.log

当进程不响应,强制输出线程快照,同时会显示是否有死锁 jstack -F pid > theadInfo.log

RUNNABLE: 线程运行中和IO等待
BLOCKED:  线程在等待Monitor锁
TIMED_WAITING: 线程在等待唤醒,设置了超时时间
WAITING: 线程在无限等待唤醒
IN_NATIVE: 反应的是线程正在运行系统“本机”代码而不是java代码

jstack输出的日志中:
1.关注是否有死锁
2.我们自己的代码是否存在大量blocked,及分析单个线程

netstat

netstat -anp |grep ‘:port’

查看我们服务监听的端口,建立的连接状态,看是否有不正常的CLOSE_WAIT

TCP会有以下几种状态,分别对应TCP三次握手、传输信息、TCP四次挥手的各个过程: listen、syn_sent、syn_revd、established、fin_wait_1、close_wait、fin_wait_2、last_ack、time_wait、closed

CLOSE_WAIT:是被动关闭连接形成的,会占用一个网络连接。
1. 客户端调用了close函数发起两次挥手,服务器接受后就会进入CLOSE_WAIT状态,客户端再接受到服务器的ACK之后则会进入到FIN_WAIT_2状态;但服务器还没有发起两次挥手,只有完成四次挥手后连接才算真正断开,此时双方才会释放对应的连接资源。
2.如果服务器接收到两次挥手后不进行调用close,那么服务器就会存在大量处于CLOSE_WAIT状态的连接,而每个连接都会占用服务器的资源,最终就会导致服务器可用资源越来越少

TIME_WAIT: 客户端主动关闭连接时,发送最后一个ACK后,然后会进入TIME_WAIT状态,再停留两个最大报文生存时间(2MLS)进入CLOSE状态

参考

https://blog.csdn.net/sulijin/article/details/124412379
https://www.nowcoder.com/discuss/388301958082293760

猜你喜欢

转载自blog.csdn.net/u013565163/article/details/130631260
今日推荐