Java程序突然挂掉

问题:

服务经常性突然挂掉,查看服务没有任何报错信息

排查过程:

1.思考可能引起服务挂掉的原因

(1)java本身发生OOM,即日志中打印"java.lang.OutOfMemoryError: Java heap space"

(2)被linxu操作系统执行OOM-Killer

2.首先查看服务器监控数据,发现该服务jvm内存使用正常,查看服务日志也没有发现打印OutOfMemoryError异常信息,可以排除此原因。

怀疑:有可能Java进程本身没有内存过高被杀,但是这个进程当时占用的内存过高,挤占了OS内核空间, 直接被操作系统触发OOM-Killer给杀死了

(1)查看java进程数据

[ticket@iZ2ze0uo1c6bfj8d9lck63Z log]$ dmesg | grep java
[50380153.821507] java invoked oom-killer: gfp_mask=0x201da, order=0, oom_score_adj=0
[50380153.821512] java cpuset=/ mems_allowed=0
[50380153.821516] CPU: 0 PID: 19176 Comm: java Tainted: G           OE  ------------ T 3.10.0-1062.1.2.el7.x86_64 #1
[50380153.821784] [ 5424]  1000  5424   876540    24047     156        0             0 java
[50380153.821792] [18875]  1000 18875  1280393   698641    1482        0             0 java
[50380153.821818] Out of memory: Kill process 18875 (java) score 750 or sacrifice child
[50380153.822757] Killed process 18875 (java), UID 1000, total-vm:5121572kB, anon-rss:2794564kB, file-rss:0kB, shmem-rss:0kB

(2)查看被系统杀死的进程

[ticket@iZ2ze0uo1c6bfj8d9lck63Z log]$ dmesg | egrep -i 'killed process'
[50380153.822757] Killed process 18875 (java), UID 1000, total-vm:5121572kB, anon-rss:2794564kB, file-rss:0kB, shmem-rss:0kB

发现我的Java应用确实被 kill 了, 内存占用接近3G

(3)确定发生oom

[ticket@iZ2ze0uo1c6bfj8d9lck63Z log]$ dmesg -T | grep 'Out of memory'
[Wed Jul 20 16:58:23 2022] Out of memory: Kill process 18875 (java) score 750 or sacrifice child

结论:

确实是因为内存占用过高导致被Linux杀死

解决方案:

1.检查java进程堆栈情况:

(1)输入命令:top -c,查看占用内存过高的进程信息

(2)输入命令:jmap -histo:live PID > xxx.log,vim查看内存中的存活对象统计,找出业务相关的类名

(3)如果第(2)步仍然不能定位到代码中的具体对象,输入命令:jmap -dump:live,format=b,file=xxx.hprof PID

这个命令会将内存里的所有信息都输出,生成hprof文件。我16G的内存占用,输出的文件大小为1.6G。注意:这个命令会导致应用暂时挂起,所以谨慎使用。我的应用当时挂起了约10s。

(4)文件大小不是很大的话,使用jdk自带的jhat命令即可,输入命令:jhat -J-mx2G -port 7170,该命令可以查看内存占用的对象

(5)如果文件太大,可以下载到本地使用jdk自带的 jvisualvm 工具进行分析。

2调整jvm配置,官方建议是机器物理内存的60%

  • -Xms设置堆的最小空间大小。
  • -Xmx设置堆的最大空间大小。
  • -Xmn:设置年轻代大小
  • -XX:NewSize设置新生代最小空间大小。
  • -XX:MaxNewSize设置新生代最大空间大小。
  • -XX:PermSize设置永久代最小空间大小。
  • -XX:MaxPermSize设置永久代最大空间大小。
  • -Xss设置每个线程的堆栈大小
  • -XX:+UseParallelGC:选择垃圾收集器为并行收集器。此配置仅对年轻代有效。即上述配置下,年轻代使用并发收集,而年老代仍旧使用串行收集。
  • -XX:ParallelGCThreads=20:配置并行收集器的线程数,即:同时多少个线程一起进行垃圾回收。此值最好配置与处理器数目相等。

典型JVM参数配置参考:

  • java-Xmx3550m-Xms3550m-Xmn2g-Xss128k
  • -XX:ParallelGCThreads=20
  • -XX:+UseConcMarkSweepGC-XX:+UseParNewGC

-Xmx3550m:设置JVM最大可用内存为3550M。

-Xms3550m:设置JVM促使内存为3550m。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。

-Xmn2g:设置年轻代大小为2G。整个堆大小=年轻代大小+年老代大小+持久代大小。持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,官方推荐配置为整个堆的3/8。

-Xss128k:设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。更具应用的线程所需内存大 小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000 左右。

史上最全的JVM配置参数大全_jvm参数配置详解_平平无奇小菜鸟。的博客-CSDN博客
3.增加物理机内存;

你可能感兴趣的:(spring,spring,boot,jetty,servlet,后端)