springboot项目部署在linux中,出现了OOM(Java heap space),记录一下排查流程
1、由于项目并没有设置jvm的属性,所以先查看一下默认的内存有多大
#在Java环境中获取堆内存大小的信息
java -XX:+PrintFlagsFinal -version | grep HeapSize
在linux中执行这段命令,会得到
uintx ErgoHeapSizeLimit = 0 {product}
uintx HeapSizePerGCThread = 87241520 {product}
uintx InitialHeapSize := 125829120 {product}
uintx LargePageHeapSizeThreshold = 134217728 {product}
uintx MaxHeapSize := 2006974464 {product}
ErgoHeapSizeLimit:这是Ergonomics堆大小限制,它是根据系统配置和运行时情况自动调整的。
HeapSizePerGCThread:这是每个垃圾回收线程的堆大小,它指定了每个垃圾回收线程可以使用的堆内存量。
InitialHeapSize:这是Java虚拟机在启动时分配的初始堆大小。
LargePageHeapSizeThreshold:这是启用大页内存的阈值,当堆大小达到或超过该阈值时,Java虚拟机将尝试使用大页内存。
MaxHeapSize:这是Java虚拟机允许的最大堆大小。当堆的大小达到这个限制时,Java虚拟机将停止分配更多的内存。
2、获取指定 Java 进程的堆内存信息。
#获取指定 Java 进程的堆内存信息。 <PID>是自己的程序PID
sudo jcmd <PID> GC.heap_info
我执行这段代码是出现了jcmd: command not found错误,原因是jcmd命令的路径没有包含在sudo的环境变量中。
那么可以使用绝对路径来执行jcmd命令
#获取java路径
which java
得到绝对路径之后再去执行就可以了
#使用绝对路径执行jcmd命令 <PID>是自己的程序PID
sudo /usr/local/jdk1.8.0_371/bin/jcmd <PID> GC.heap_info
可以得到这么样的一个结果
PSYoungGen total 461824K, used 204150K [0x00000000d8200000, 0x00000000ff280000, 0x0000000100000000)
eden space 283648K, 71% used [0x00000000d8200000,0x00000000e495d838,0x00000000e9700000)
from space 178176K, 0% used [0x00000000f4480000,0x00000000f4480000,0x00000000ff280000)
to space 177664K, 0% used [0x00000000e9700000,0x00000000e9700000,0x00000000f4480000)
ParOldGen total 971264K, used 232467K [0x0000000088600000, 0x00000000c3a80000, 0x00000000d8200000)
object space 971264K, 23% used [0x0000000088600000,0x0000000096904ee0,0x00000000c3a80000)
Metaspace used 104851K, capacity 109680K, committed 111064K, reserved 1146880K
class space used 12467K, capacity 13257K, committed 13528K, reserved 1048576K
根据提供的堆内存信息,可以得到以下解释:
PSYoungGen 是年轻代的名称,表示新生代堆内存。
total 461824K:新生代总大小为 461824K(约 451 MB)。
used 204150K:新生代已使用的大小为 204150K(约 199 MB)。
[0x00000000d8200000, 0x00000000ff280000, 0x0000000100000000):新生代的内存地址范围。
eden space:表示 Eden 区的大小和使用情况。
283648K:Eden 区的大小为 283648K(约 277 MB)。
71% used:Eden 区已使用的比例为 71%。
from space:表示 Survivor From 区的大小和使用情况。
178176K:Survivor From 区的大小为 178176K(约 174 MB)。
0% used:Survivor From 区未被使用。
to space:表示 Survivor To 区的大小和使用情况。
177664K:Survivor To 区的大小为 177664K(约 173 MB)。
0% used:Survivor To 区未被使用。
ParOldGen 是老年代的名称,表示老年代堆内存。
total 971264K:老年代总大小为 971264K(约 948 MB)。
used 232467K:老年代已使用的大小为 232467K(约 227 MB)。
[0x0000000088600000, 0x00000000c3a80000, 0x00000000d8200000):老年代的内存地址范围。
Metaspace:表示元数据空间(Metaspace)的使用情况。
used 104851K:元数据空间已使用的大小为 104851K(约 102 MB)。
capacity 109680K:元数据空间的容量为 109680K(约 107 MB)。
committed 111064K:元数据空间的已分配大小为 111064K(约 108 MB)。
reserved 1146880K:元数据空间的保留大小为 1146880K(约 1122 MB)。
class space:表示类空间的使用情况。
used 12467K:类空间已使用的大小为 12467K(约 12 MB)。
capacity 13257K:类空间的容量为 13257K(约 13 MB)。
committed 13528K:类空间的已分配大小为 13528K(约 13 MB)。
reserved 1048576K:类空间的保留大小为 1048576K(约 1024 MB)。
这些信息描述了 Java 进程的堆内存使用情况,包括新生代、老年代、元数据空间和类空间的大小和使用情况。
3、分析 Java 堆内存的使用情况和对象分布
#分析 Java 堆内存的使用情况和对象分布 <PID>是自己的程序PID
sudo /usr/local/jdk1.8.0_371/bin/jmap -histo <PID>
这个命令会得到一串很长的堆内存的使用情况,如果太长展示不如来的话可以 通过管道符查看指定行数
sudo /usr/local/jdk1.8.0_371/bin/jmap -histo 1850336 | head -n <行数>
4、查看服务器物理内存
#显示系统内存的使用情况
free -h
total:表示系统内存的总大小。
used:表示已使用的内存大小。
free:表示可用的空闲内存大小。
shared:表示被共享的内存大小。
buffers:表示被缓冲的内存大小。
cached:表示被缓存的内存大小。
5、生成.hprof 文件进行分析
#生成.hprof 路径就是.hprof文件生成的地方,<PID>是自己的程序PID
sudo /usr/local/jdk1.8.0_371/bin/jmap -dump:format=b,file=/data/install/logs/file.hprof <PID>
生成文件后可以下载下来 使用JProfiler等工具进行解析
可以参考这个
https://blog.csdn.net/qq_42262444/article/details/133163454