1. 程式人生 > 其它 >CPU佔用過高排查

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

二.例子

1.top 可以看出PID 733程序 的佔用CPU 172%

2.查詢程序733下的執行緒 可以看到TID 執行緒775佔用了96%且持有了很長時間 其實到這一步基本上能猜測到應該是 肯定是那段程式碼發生了死迴圈
ps -mp 733 -o THREAD,tid,time | sort -rn

3.執行緒ID轉換為16進位制格式
printf "%x\n" 775

4.檢視java的堆疊資訊,列印30行
jstack -l pid號 |grep 0x執行緒號 -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;
        }
    }
}

在應用一啟動的時候 spring初始化的就會執行這一段處理丟失訊息的程式碼 然後這段死迴圈程式碼 沒有任何作用

解決方法 即 註釋掉whlie(true)這一段程式碼

重新部署後 cpu佔用就很正常了

本文版權歸作者所有,歡迎轉載,請務必新增原文連結。