java实战CPU占用过高问题的排查及解决

最近一段时间 某台服务器上的一个应用总是隔一段时间就自己挂掉 用top看了看 从重新部署应用开始没有多长时间CPU占用上升得很快

排查步骤

1.使用top 定位到占用CPU高的进程PID

top

2.通过ps aux | grep PID命令

获取线程信息,并找到占用CPU高的线程

ps -mp pid -o THREAD,tid,time | sort -rn

3.将需要的线程ID转换为16进制格式

printf "%x\n" tid

4.打印线程的堆栈信息 到了这一步具体看堆栈的日志来定位问题了

jstack pid |grep tid -A 30

top 可以看出PID 733进程 的占用CPU 172%

查找进程733下的线程 可以看到TID 线程775占用了96%且持有了很长时间 其实到这一步基本上能猜测到应该是 肯定是那段代码发生了死循环

ps -mp 733 -o THREAD,tid,time | sort -rn

线程ID转换为16进制格式

printf "%x\n" 775

查看java 的堆栈信息

jstack 733 |grep 307 -A 30

显然是 SmsQueueServiceImpl 中的produceMissSms 和 consumeMissSms 方法有问题

一下为精简的部分代码

/** * Created by dongxc on 2015/7/7. 通知消息队列 */
@Service("smsQueueService")
public class SmsQueueServiceImpl {
 // 生产异常队列方法
 public void produceMissSms(SmsLogDo smsLogDo) {
  /*
   * try{ String key = EnumRedisPrefix.SMS_QUEUE_MISS_DEAL.getValue(); boolean result = redisService.lpush(key,
   * smsLogDo, 0); if(result==false){ logger.error("通知消息异常队列生产消息返回失败!"+smsLogDo.getId()); } }catch(Exception e){
   * logger.error("通知消息异常队列生产消息失败!", e); }
   */
 }

 // 消费异常队列方法
 public SmsLogDo consumeMissSms() {
  try {
   String destKey = EnumRedisPrefix.SMS_QUEUE_MISS_DEAL.getValue();
   SmsLogDo smsLogDo = new SmsLogDo();
   Object obj = null;
   if (obj == null) {
    return null;
   } else {
    smsLogDo = (SmsLogDo) obj;
   }
   return smsLogDo;
  } catch (Exception e) {
   logger.error("通知消息队列消费方法失败!", e);
   return null;
  }
 }
}

从很有年代感的垃圾代码来看 这两个方法并没有什么问题 继续往调用这两个方法的上层排查

/**
 * Created by dongxc on 2015/7/7.
 * 消息通知监控线程
 */
@Service("smsMonitorComsumer")
public class SmsMonitorComsumerImpl {

 @Autowired
 private SmsQueueServiceImpl smsQueueService;

 //取队列里的任务消费
 @Transactional(propagation= Propagation.NOT_SUPPORTED)
 public void run() {

 while (true) {
   try {
    SmsLogDo smsLogDo = smsQueueService.consumeMissSms();
    Boolean result = false;
    if(smsLogDo!=null){
     long diff = (new Date()).getTime() - smsLogDo.getSendtime().getTime() ;
     long min = diff%(1000*24*60*60)%(1000*60*60)/(1000*60);//计算差多少分钟
     if(min>5){
      result = true;
     }
    }
    if(result){
     smsQueueService.produceSms(smsLogDo);
    }else{
     smsQueueService.produceMissSms(smsLogDo);
    }
   } catch (Exception ex) {
    try{
     Thread.sleep(3000);
    }catch(Exception e){
     //logger.error("发送站内信息短信时线程执行失败2!", e);
    }
   }
  }

 }
}

很显然 这里有一个while(true) 基本定位到问题了 while里面完全是没有用的代码

继续往上层看谁来调用

/**
 * Created by dongxc on 2015/7/7.
 * 通知消息队列
 */
@Service("smsLogRunThread")
public class SmsLogRunThreadImpl {
 public int flag;
 @Autowired
 private SmsLogConsumerImpl smsLogConsumer;
 @Autowired
 private SmsMonitorComsumerImpl smsMonitorComsumer;

 @PostConstruct
 public void init() {

  if(ip!=""&&host!=""&&ip.equals(host)){
   Thread thread = new Thread(){
    public void run() {
     smsLogConsumer.run();
    }
   };
   thread.start();
   Thread thread1 = new Thread(){
    public void run() {
     smsMonitorComsumer.run();
    }
   };
   thread1.start();
  }

 }
}

在应用一启动的时候 spring初始化的就会执行这一段处理丢失消息的代码 然后这段死循环代码 没有任何作用

解决方法 即 注释掉whlie(true)这一段代码

案例一下,其实之前也遇到过CPU占用很高的问题, 但是那次是 频繁的GC导致的

其实排查问题 的过程中也是在不断的学习的过程

(0)

相关推荐

  • java应用cpu占用过高问题分析及解决方法

    使用jstack分析java程序cpu占用率过高的问题 1,使用jps查找出java进程的pid,如3707 2,使用top -p 14292 -H观察该进程中所有线程的CPU占用. [root@cp01-game-dudai-0100.cp01.baidu.com ~]# top -p 14292 -H top - 22:14:13 up 33 days, 7:29, 4 users, load average: 25.68, 32.11, 33.76 Tasks: 113 total, 2

  • 一次因Java应用造成CPU过高的排查实践过程

    前言 最近遇到一个java应用造成了服务器CPU使用率过高,最后查询,问题是因为在tomcat下重新部署应用的时候没有kill掉tomcat进程,造成应用中的数据库连接池进程中的锁不能被释放,死循环造成了cpu使用率过高的现象,详细原因就不做详细分析了,主要分享一下问题排查的过程. 使用top命令查询服务cpu使用情况 服务器资源使用率 可以看到31737这个进程的CPU使用率巨大 使用top -Hp 31737查询31737进程中各个线程的资源使用率 top -Hp 31737 使用top -

  • java实战CPU占用过高问题的排查及解决

    最近一段时间 某台服务器上的一个应用总是隔一段时间就自己挂掉 用top看了看 从重新部署应用开始没有多长时间CPU占用上升得很快 排查步骤 1.使用top 定位到占用CPU高的进程PID top 2.通过ps aux | grep PID命令 获取线程信息,并找到占用CPU高的线程 ps -mp pid -o THREAD,tid,time | sort -rn 3.将需要的线程ID转换为16进制格式 printf "%x\n" tid 4.打印线程的堆栈信息 到了这一步具体看堆栈的日

  • 记一次tomcat进程cpu占用过高的问题排查记录

    本文主要记录一次tomcat进程,因TCP连接过多导致CPU占用过高的问题排查记录. 问题描述 linux系统下,一个tomcat web服务的cpu占用率非常高,top显示结果超过200%.请求无法响应.反复重启依然同一个现象. 问题排查 1.获取进程信息 通过jdk提供的jps命令可以快速查出jvm进程, jps pid 2.查看jstack信息 jstack pid 发现存在大量log4j线程block,处于waiting lock状态 org.apache.log4j.Category.

  • Java进程cpu占用过高问题解决

    cpu是时分(time division)的,操作系统里有很多线程,每个线程的运行时间由cpu决定,cpu会分给每个线程一个时间片,时间片是一个很短的时间长度,如果在时间片内,线程一直占有,则是100%:我们应该意识到,cpu运行速度很快(主频非常高),除非密集型耗费cpu的运算,其它类型任务都会在小于时间片的时间内结束. 产生CPU100%的原因: 某一程序一直占用CPU是导致CPU100%的原因,大概有以下几种情况: 1.Java 内存不够或溢出导致GC overhead问题, GC ove

  • JVM---jstack分析Java线程CPU占用,线程死锁的解决

    本文章主要演示在Windows环境,Linux环境也差不多. 一.分析CPU占用飙高 首先写一个Java程序,并模拟一个死循环.让CPU使用率飙高.CPU负载过大的话,新的请求就处理不了了,这就是很多程序变慢了甚至不能访问的原因之一. 下面是我这里的Controller,启动程序之后,开多个请求访问这个方法.死循环代码就不贴了,自己构造.我这里模拟的一个截取字符串的死循环. /** * 演示死循环导致cpu使用率飙高 * */ @RequestMapping("/loop") publ

  • arthas排查jvm中CPU占用过高问题解决

    目录 安装 小试 找出CPU的元凶 查看线程栈的参数 安装 小试 记一次使用arthas排查jvm中CPU占用过高问题.这工具屌爆了 碾压我目前使用的全部JVM工具. curl -O https://arthas.aliyun.com/arthas-boot.jar java -jar arthas-boot.jar --repo-mirror aliyun --use-http jar后面的参数也可以不加 加上只是为了下载速度更快 接下来arthas 控制台中显示了当前机器上jvm进程列表 输

  • 在windows下揪出java程序占用cpu很高的线程并完美解决

    我的一个java程序偶尔会出现cpu占用很高的情况 一直不知道什么原因 今天终于抽时间解决了 系统是win2003 jvisualvm 和 jconsole貌似都只能看到总共占用的cpu 看不到每个线程分别占用的cpu呢所以在windows平台上要找出到底是哪个线程占用的cpu还不那么容易,linux用top就简单多了 最后的解决方法: 1.找到java进程对应的pid. 找pid的方法是:打开任务管理器,然后点击 "查看" 菜单,然后点击 "选择列",把pid勾上

  • Java多线程导致CPU占用100%解决及线程池正确关闭方式

    简介 情景:1000万表数据导入内存数据库,按分页大小10000查询,多线程,15条线程跑. 使用了ExecutorService executor = Executors.newFixedThreadPool(15) 本地跑了一段时间后,发现电脑CPU逐渐升高,最后CPU占用100%卡死,内存使用也高达80%. 排查问题 Debug 发现虽然创建了定长15的线程池,但是因为数据量大,在For中循环分页查询的List会持续加入LinkedBlockingQueue() 队列中每一个等待的任务,又

  • 如何定位java程序中占用cpu最高的线程堆栈信息

    找出占用cpu最高的线程堆栈信息 在java编码中,有时会因为粗心导致cpu占用较高的情况,为了避免影响程序的正常运行,需要找到问题并解决.这里模拟一个cpu占用较高的场景,并尝试定位到代码行. 示例代码如下: public class Math { public static final int initData = 666; public static User user = new User(); public int compute() { //一个方法对应一块栈帧内存区域 int a

  • Mysql CPU占用高的问题解决方法小结

    通过以前对mysql的操作经验,先将mysql的配置问题排除了,查看msyql是否运行正常,通过查看mysql data目录里面的*.err文件(将扩展名改为.txt)记事本查看即可.如果过大不建议用记事本了,容易死掉,可以用editplus等工具 简单的分为下面几个步骤来解决这个问题: 1.mysql运行正常,也有可能是同步设置问题导致 2.如果mysql运行正常,那就是php的一些sql语句导致问题发现,用root用户进入mysql管理mysql -u root -p输入密码mysql:sh

随机推荐