相关关键词: java8、jmap、jstack、jstat、netstat、less 、grep、 jvm
复盘一下之前遇到过的OOM问题的排查过程。业务细节暂不表,表象:应用假死,接口请求无法响应, 主要问题是业务量增加,有一个核心业务会有byte[],以及堆设置的比较小。处理过程,优化byte[]的过程,增加堆的大小。
排查过程:
1.jmap输出堆的使用情况
2.jstat输出GC信息
3.jstack 输出线程堆栈快照
4.netstat查看监听端口的TCP连接状态
5.查看日志中是否有OutOfMemory错误
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: 老年代
jmap -histo:live 29296 |head -n 10
通过这个命令查看是否有不正常的对象占用太多内存导致内存泄漏
语法: jmap -dump:format=b,file=heap.bin
通过上面命令输出堆的转储二进制文件,通过eclipse的jconsole分析我们java程序的内存
-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: 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生成当前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 -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