java排查一个线上死循环cpu暴涨的过程分析
作者:java的爪哇 发布时间:2022-07-20 01:27:08
问题,打一个页面cpu暴涨,打开一次就涨100%,一会系统就卡的不行了。
排查方法,因为是线上的linux,没有用jvm监控工具rim链接上去。
只好用命令排查:
top cpu排序,一个java进程cpu到500%了,什么鬼.....
查到对应java进程
jps || ps -aux | grep 端口
pid=13455
查看进程中线程使用情况 T排序 查看cpu占用time最高的线程编号
top -Hp 13455
有个线程9877 的时间一直在爆涨
获取线程十六进制地址9877 (十六进制一定要小写)
printf "%x\n" 9877
执行 jstack 13455|grep -10 2695(线程十六进制号)
如果想查看完整信息,可导出文本,查找
jstack -l 9839 > jstack.log-9893
"qtp750044075-25" #25 prio=5 os_prio=0 tid=0x00007f83354e5000 nid=0x2695 runnable [0x00007f830e5d8000]
java.lang.Thread.State: RUNNABLE
at java.text.DateFormatSymbols.<init>(DateFormatSymbols.java:145)
at sun.util.locale.provider.DateFormatSymbolsProviderImpl.getInstance(DateFormatSymbolsProviderImpl.java:85)
at java.text.DateFormatSymbols.getProviderInstance(DateFormatSymbols.java:364)
at java.text.DateFormatSymbols.getInstance(DateFormatSymbols.java:340)
at java.util.Calendar.getDisplayName(Calendar.java:2110)
at java.text.SimpleDateFormat.subFormat(SimpleDateFormat.java:1125)
at java.text.SimpleDateFormat.format(SimpleDateFormat.java:966)
at java.text.SimpleDateFormat.format(SimpleDateFormat.java:936)
at java.text.DateFormat.format(DateFormat.java:345)
at com.huiwan.gdata.modules.gdata.util.TimeUtil.getDay(TimeUtil.java:383)
at com.huiwan.gdata.modules.gdata.publ.retain.service.impl.Retain3ServiceImpl.act(Retain3ServiceImpl.java:119)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
.......略
Locked ownable synchronizers:
- None
定住到
Retain3ServiceImpl.java:119
这行,马的,有人写了个while循环,用字符串时间比较,之前表是date类型,后改为datetime类型,多了00:00:00永远也没一样的时间,一直在那while.....还搞了个json对象默认加0......
改了这里的代码,就好了,cpu就没上去了.
补充知识:记一次线上Java程序导致服务器CPU占用率过高的问题排除过程
1、故障现象
客服同事反馈平台系统运行缓慢,网页卡顿严重,多次重启系统后问题依然存在,使用top命令查看服务器情况,发现CPU占用率过高。
2、CPU占用过高问题定位
2.1、定位问题进程
使用top命令查看资源占用情况,发现pid为14063的进程占用了大量的CPU资源,CPU占用率高达776.1%,内存占用率也达到了29.8%
[ylp@ylp-web-01 ~]$ top
top - 14:51:10 up 233 days, 11:40, 7 users, load average: 6.85, 5.62, 3.97
Tasks: 192 total, 2 running, 190 sleeping, 0 stopped, 0 zombie
%Cpu(s): 97.3 us, 0.3 sy, 0.0 ni, 2.5 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 16268652 total, 5114392 free, 6907028 used, 4247232 buff/cache
KiB Swap: 4063228 total, 3989708 free, 73520 used. 8751512 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
14063 ylp 20 0 9260488 4.627g 11976 S 776.1 29.8 117:41.66 java
2.2、定位问题线程
使用ps -mp pid -o THREAD,tid,time命令查看该进程的线程情况,发现该进程的多个线程占用率很高
[ylp@ylp-web-01 ~]$ ps -mp 14063 -o THREAD,tid,time
USER %CPU PRI SCNT WCHAN USER SYSTEM TID TIME
ylp 361 - - - - - - 02:05:58
ylp 0.0 19 - futex_ - - 14063 00:00:00
ylp 0.0 19 - poll_s - - 14064 00:00:00
ylp 44.5 19 - - - - 14065 00:15:30
ylp 44.5 19 - - - - 14066 00:15:30
ylp 44.4 19 - - - - 14067 00:15:29
ylp 44.5 19 - - - - 14068 00:15:30
ylp 44.5 19 - - - - 14069 00:15:30
ylp 44.5 19 - - - - 14070 00:15:30
ylp 44.5 19 - - - - 14071 00:15:30
ylp 44.6 19 - - - - 14072 00:15:32
ylp 2.2 19 - futex_ - - 14073 00:00:46
ylp 0.0 19 - futex_ - - 14074 00:00:00
ylp 0.0 19 - futex_ - - 14075 00:00:00
ylp 0.0 19 - futex_ - - 14076 00:00:00
ylp 0.7 19 - futex_ - - 14077 00:00:15
从输出信息可以看出,14065~14072之间的线程CPU占用率都很高
2.3、查看问题线程堆栈
挑选TID为14065的线程,查看该线程的堆栈情况,先将线程id转为16进制,使用printf "%x\n" tid命令进行转换
[ylp@ylp-web-01 ~]$ printf "%x\n" 14065
36f1
再使用jstack命令打印线程堆栈信息,命令格式:jstack pid |grep tid -A 30
[ylp@ylp-web-01 ~]$ jstack 14063 |grep 36f1 -A 30
"GC task thread#0 (ParallelGC)" prio=10 tid=0x00007fa35001e800 nid=0x36f1 runnable
"GC task thread#1 (ParallelGC)" prio=10 tid=0x00007fa350020800 nid=0x36f2 runnable
"GC task thread#2 (ParallelGC)" prio=10 tid=0x00007fa350022800 nid=0x36f3 runnable
"GC task thread#3 (ParallelGC)" prio=10 tid=0x00007fa350024000 nid=0x36f4 runnable
"GC task thread#4 (ParallelGC)" prio=10 tid=0x00007fa350026000 nid=0x36f5 runnable
"GC task thread#5 (ParallelGC)" prio=10 tid=0x00007fa350028000 nid=0x36f6 runnable
"GC task thread#6 (ParallelGC)" prio=10 tid=0x00007fa350029800 nid=0x36f7 runnable
"GC task thread#7 (ParallelGC)" prio=10 tid=0x00007fa35002b800 nid=0x36f8 runnable
"VM Periodic Task Thread" prio=10 tid=0x00007fa3500a8800 nid=0x3700 waiting on condition
JNI global references: 392
从输出信息可以看出,此线程是JVM的gc线程。此时可以基本确定是内存不足或内存泄露导致gc线程持续运行,导致CPU占用过高。
所以接下来我们要找的内存方面的问题
3、内存问题定位
3.1、使用jstat -gcutil命令查看进程的内存情况
[ylp@ylp-web-01 ~]$ jstat -gcutil 14063 2000 10
S0 S1 E O P YGC YGCT FGC FGCT GCT
0.00 0.00 100.00 99.99 26.31 42 21.917 218 1484.830 1506.747
0.00 0.00 100.00 99.99 26.31 42 21.917 218 1484.830 1506.747
0.00 0.00 100.00 99.99 26.31 42 21.917 219 1496.567 1518.484
0.00 0.00 100.00 99.99 26.31 42 21.917 219 1496.567 1518.484
0.00 0.00 100.00 99.99 26.31 42 21.917 219 1496.567 1518.484
0.00 0.00 100.00 99.99 26.31 42 21.917 219 1496.567 1518.484
0.00 0.00 100.00 99.99 26.31 42 21.917 219 1496.567 1518.484
0.00 0.00 100.00 99.99 26.31 42 21.917 220 1505.439 1527.355
0.00 0.00 100.00 99.99 26.31 42 21.917 220 1505.439 1527.355
0.00 0.00 100.00 99.99 26.31 42 21.917 220 1505.439 1527.355
从输出信息可以看出,Eden区内存占用100%,Old区内存占用99.99%,Full GC的次数高达220次,并且频繁Full GC,Full GC的持续时间也特别长,平均每次Full GC耗时6.8秒(1505.439/220)。根据这些信息,基本可以确定是程序代码上出现了问题,可能存在不合理创建对象的地方
3.2、分析堆栈
使用jstack命令查看进程的堆栈情况
[ylp@ylp-web-01 ~]$ jstack 14063 >>jstack.out
把jstack.out文件从服务器拿到本地后,用编辑器查找带有项目目录并且线程状态是RUNABLE的相关信息,从图中可以看出ActivityUtil.java类的447行正在使用HashMap.put()方法
3.3、代码定位
打开项目工程,找到ActivityUtil类的477行,代码如下:
找到相关同事了解后,这段代码会从数据库中获取配置,并根据数据库中remain的值进行循环,在循环中会一直对HashMap进行put操作。
查询数据库中的配置,发现remain的数量巨大
至此,问题定位完毕。
来源:https://blog.csdn.net/liangrui1988/article/details/79230480
猜你喜欢
- Android从网络中获得一张图片并显示在屏幕上的实例详解看下实现效果图:1:androidmanifest.xml的内容<?xml
- 情景描述将一个时间转换为对应的unix时间戳,字符集使用UTF-8编码,数据通讯统一采用 HTTP 协议通讯,使用POST 方法请求并传递参
- SpringBoot集成Mybatis时mybatis.mapper-locations和@MapperScan的作用1、mybatis.m
- 重新启动IDEA maven项目SSM框架所有@注解失效,每个文件上都有个小黄圆,而且我发现所有构建项目的maven的jar包都不在了,也就
- 如何通过Java发送HTTP请求,通俗点讲,如何通过Java(模拟浏览器)发送HTTP请求。Java有原生的API可用于发送HTTP请求,即
- 本文实例讲述了JavaMail实现发送超文本(html)格式邮件的方法。分享给大家供大家参考。具体如下:附件以超文本形式,很常用,与普通的邮
- 本文实例讲述了C#实现的WINDOWS登录功能。分享给大家供大家参考,具体如下:using System;using System.Data
- Java通过证书访问Https请求创建证书管理器类import java.io.FileInputStream;import java.se
- 软件工程由于需要不断迭代开发,因此要对源代码进行版本管理。Android源代码工程(AOSP)也不例外,它采用Git来进行版本管理。AOSP
- 一、推迟执行动作可以使用timer+map方法实现.代码如下:Observable.timer(5, TimeUnit.MILLISECON
- 前言老规矩,还是从最简单粗暴的开始。那么多简单算简单?多粗暴算粗暴?我告诉你可以不写一句代码,你信吗?直接把一个文件往IIS服务器上一扔,就
- 引导语上一小节我们学习了 Socket,本文我们来看看服务端套接字 API:ServerSocket,本文学习完毕之后,我们就可以把客户端
- 给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。示例 1:输入: 1->1->2输出: 1->2示例 2:输
- Android Studio生成的APP默认图标是经典的机器人图标。可以通过Android Studio实现APP图标和名称的修改。1 修改
- 最近为公司做的一个Demo里面用到了ScrollView嵌套了GridView和ListView,然而在嵌套的时候我发现GridView和L
- 在前面的《基于任务的异步编程模式(TAP)》文章中讲述了.net 4.5框架下的异步操作自我实现方式,实际上,在.net 4.5中部分类已实
- 看完本文你将了解:ACTION_CANCEL的触发时机滑出子View区域会发生什么?为什么不响应onClick()事件首先看一下官方的解释:
- 前言有时候我们在项目中,会用到一些本地 jar 包文件,比如隔壁公司自己打包的;此时无法从maven远程仓库拉取;那么我们可以考虑把 jar
- 本文实例讲述了Android控件之CheckBox、RadioButton用法。分享给大家供大家参考。具体如下:CheckBox和Radio
- 本文将引导大家做一个音乐播放器,在做这个Android开发实例的过程中,能够帮助大家进一步熟悉和掌握学过的List