線上linux系統(tǒng)故障排查之一:CPU使用率過高

《線上linux系統(tǒng)故障排查之一:CPU使用率過高》
《線上linux系統(tǒng)故障排查之二:內(nèi)存占用過高》

一個應(yīng)用占用CPU很高泽裳,除了確實是計算密集型應(yīng)用之外,通常原因都是出現(xiàn)了死循環(huán)坏挠。
下面我們將一步步定位問題师骗,詳盡的介紹每一步驟的相關(guān)知識屁擅。

一仲义、通過top命令定位占用cpu高的進程

執(zhí)行top命令得到以下結(jié)果:


top命令執(zhí)行結(jié)果

通過上圖可以明顯看出進程PID41843占用cpu過高,明顯存在問題杠巡,定位到了進程id量窘。當然如果你想只觀察進程PID41843的CPU和內(nèi)存以及負載情況,可以使用以下命令

top -p 41843氢拥。

結(jié)果如下:


top -p 41843命令執(zhí)行結(jié)果

這里順便解釋下上圖各個參數(shù)的意義蚌铜,有利于讀者更好的排查問題。

  1. 第一行是任務(wù)隊列信息
    top - 14:06:34 up 537 days, 6 min, 6 users, load average: 0.41, 0.45, 0.43
任務(wù)隊列信息 含義
14:06:34 當前時間
537 days 系統(tǒng)運行時間
6 min 用戶在線時間
6 users 在線用戶數(shù)
load average: 0.41, 0.45, 0.43 系統(tǒng)負載兄一,即任務(wù)隊列的平均長度厘线。1分鐘前、5分鐘前出革、15分鐘前平均負載

2)第二行為進程的信息

進程信息 含義
Tasks: 1 total 進程總數(shù)
0 running 正在運行的進程數(shù)
1 sleeping 睡眠的進程數(shù)
0 stopped 停止的進程數(shù)
0 zombie 僵尸進程數(shù)
  1. 第三行為cpu信息
cpu信息 含義
6.1% us 用戶空間占用CPU百分比
1.5% sy 內(nèi)核空間占用CPU百分比
0.0% ni 用戶進程空間內(nèi)改變過優(yōu)先級的進程占用CPU百分比
92.2% id 空閑CPU百分比
0.0% wa 等待輸入輸出的CPU時間百分比
0.0% hi 硬件中斷
0.0% si 軟件中斷
0.0%st 實時
  1. 第四造壮、五行為內(nèi)存信息。
    內(nèi)容如下:
物理內(nèi)存信息 含義
Mem: 191272k total 物理內(nèi)存總量
173656k used 使用的物理內(nèi)存總量
17616k free 空閑內(nèi)存總量
22052k buffers 用作內(nèi)核緩存的內(nèi)存量
交換區(qū)信息 含義
Swap: 192772k total 交換區(qū)總量
0k used 使用的交換區(qū)總量
192772k free 空閑交換區(qū)總量
123988k cached 緩沖的交換區(qū)總量

二、通過top命令定位問題進程中每個線程占用cpu情況

通過問題進程中每個線程占用cpu情況使用可以使用如下命令:

top -p 41843 -H

查看進程PID41843的每一個線程占用CPU情況耳璧,如圖成箫。


top -p 41843 -H的執(zhí)行結(jié)果

由上圖明顯可以發(fā)現(xiàn),線程PID41892CPU占用率最高旨枯,接下來定位該線程的代碼是否出現(xiàn)異常導(dǎo)致cpu占用過高蹬昌。

三、通過jstack 命令定位問題代碼

上一步發(fā)現(xiàn)PID41892占用的CPU過高攀隔,就將這個PID轉(zhuǎn)換成16進制皂贩,易知,PID41892轉(zhuǎn)化成16進制為a3a4昆汹。使用如下命令命令定位問題代碼:

jstack 41892 | grep a3a4

輸出如下:

"Thread" prio=10 tid=0x00007f950043e000 nid=0x54ee in test()明刷;

可以分析得到: 線程Thread下的wait()函數(shù)cpu使用率很高,查看源代碼中的test()函數(shù)代碼如下:

public void test(){
  while(true){
     for(int i = 0 ;i<100;i++);
  }
}

while循環(huán)無法結(jié)束满粗,一直搶占cpu辈末,導(dǎo)致程序cpu使用過高,修改代碼即可映皆。
到此為止,因為代碼問題導(dǎo)致的cpu使用過高的故障排查方法就介紹完了捅彻。

tips:由于內(nèi)存的原因沟饥,頻繁的GC添怔,也可能導(dǎo)致cpu使用過高湾戳,內(nèi)存的解決方案在文章《線上linux系統(tǒng)故障排查之二:內(nèi)存占用過高》中介紹贤旷。

四砾脑、終極大殺器

筆者是喜歡一、二韧衣、三步驟定位cpu使用率過高的問題盅藻,但是如果讀者覺得以上方法不喜歡或者以上無法定位問題時,可以使用jstack方法獲取進程PID41843包含的運行線程的所有狀態(tài)畅铭。使用如下命令:

jstack -l 41843
或者將結(jié)果輸入在dump.txt文檔中:jstack -l 41843 >> dump.txt

首先我們來介紹下硕噩,Jstack的輸出中,Java線程狀態(tài)的四種狀態(tài)的概念:

RUNNABLE 線程運行中或I/O等待
BLOCKED 線程在等待monitor鎖(synchronized關(guān)鍵字)
TIMED_WAITING 線程在等待喚醒,但設(shè)置了時限
WAITING 線程在無限等待喚醒

接下來用簡單的代碼模擬這4種狀態(tài)的發(fā)生阳惹,同時介紹下問題的排查方法眶俩。
1) 讓線程一直處于RUNNABLE狀態(tài)

public static void main(String[] args) {
    printPId();//打印進程id

    runnable();//模擬RUNNABLE狀態(tài)方法,第14行
}

public static void runnable(){//第19行
    int i = 0;
    while (true) {
        i++;
    }
}

public static void printPId() {
    String name = ManagementFactory.getRuntimeMXBean().getName();
    System.out.println(name.split("@")[0]);
}

執(zhí)行main函數(shù)纲岭,使用命令jstack -l PID(pid為printPId函數(shù)打印的值)线罕,得到以下輸出信息:狀態(tài)為RUNNABLE,程序在Test類的runnable()方法中占用cpu沽翔,一般該狀態(tài)不會出現(xiàn)問題窿凤。但是如果多次執(zhí)行該命令,發(fā)現(xiàn)cpu在持續(xù)執(zhí)行該方法橘沥,且cpu使用過高夯秃,可以排查runnable()方法是否存在死循環(huán)等持續(xù)占用cpu的情況。

"main" #1 prio=5 os_prio=0 tid=0x00000000023fe000 nid=0x2ab8 runnable [0x0000000
0026df000]
java.lang.Thread.State: RUNNABLE
at Test.runnable(Test.java:19)
at Test.main(Test.java:14)

Locked ownable synchronizers:
-None

2) 讓線程一直處于BLOCKED狀態(tài)(重點關(guān)注)

public static void main(String[] args) {
    printPId();//打印進程id

    blocked();//模擬BLOCKED狀態(tài)方法仓洼,第16行
}

public static void blocked(){
    Integer lock = 0;
    new Thread() {
        public void run() {
            synchronized (lock) {
                try {
                    Thread.sleep(1000 * 1000);//26行
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }.start();

    try { Thread.sleep(100); } catch (Exception e) {e.printStackTrace();}

    synchronized (lock) {
        try {
            Thread.sleep(10 * 1000);//第37行
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

public static void printPId() {
    String name = ManagementFactory.getRuntimeMXBean().getName();
    System.out.println(name.split("@")[0]);
}

主線程sleep色建,先讓另外一個線程拿到lock,并長期持有l(wèi)ock(sleep會持有鎖箕戳,wait不會)陵吸。此時主線程會BLOCK住等待lock被釋放,此時jstack的輸出可以看到main線程狀態(tài)是BLOCKED壮虫。
根據(jù)以下輸出可以看出:
1)線程狀態(tài)是 Blocked,阻塞狀態(tài)赏酥。說明線程等待資源超時!
2)“ waiting to lock <0x00000000d6f7a970>”框都,指該地址被占用了呵晨,線程在等待給這個 0x00000000d6f7a970地址上鎖摸屠。
3)在 dump 日志里查找字符串 0x00000000d6f7a970,如果發(fā)現(xiàn)有大量線程都在等待給這個地址上鎖季二。則存在問題胯舷。繼續(xù)查找字符串0x00000000d6f7a970,發(fā)現(xiàn)locked <0x00000000d6f7a970> (a java.lang.Integer)給地址上鎖桑嘶,卻未釋放逃顶,查找該出代碼問題。
4)“waiting for monitor entry”說明此線程通過 synchronized(obj) {……} 申請進入了臨界區(qū)以政。
5)第一行里妙蔗,"main"是 Thread Name 。tid指Java Thread id。nid指native線程的id穆役。prio是線程優(yōu)先級。[0x00000000027af000]是線程棧起始地址梳杏。

"main" #1 prio=5 os_prio=0 tid=0x000000000244e000 nid=0x2218 waiting for monitor
entry [0x00000000027af000]
java.lang.Thread.State: BLOCKED (on object monitor)
at Test.blocked(Test.java:37)
-waiting to lock <0x00000000d6f7a970> (a java.lang.Integer)
at Test.main(Test.java:16)

Locked ownable synchronizers:
-None

"Thread-0" #10 prio=5 os_prio=0 tid=0x0000000058893800 nid=0x1cc8 waiting on con
dition [0x00000000599ae000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at Test$1.run(Test.java:26)
-locked <0x00000000d6f7a970> (a java.lang.Integer)

Locked ownable synchronizers:
-None

3) 讓線程處于TIMED_WAITING狀態(tài)

public static void main(String[] args) {
   printPId();//打印進程id

   timedWaiting();//模擬TIMED_WAITING狀態(tài)方法
}

public static void timedWaiting() {
    Integer lock = 0;
    synchronized (lock) {
       try {
           lock.wait(100 * 1000);
       } catch (Exception e) {
           e.printStackTrace();
       }
   }
}

public static void printPId() {
   String name = ManagementFactory.getRuntimeMXBean().getName();
   System.out.println(name.split("@")[0]);
}

根據(jù)以下輸出可以看出:
1)“TIMED_WAITING ”中的 timed_waiting 指等待狀態(tài)十性,但這里指定了時間,到達指定的時間后自動退出等待狀態(tài)楷掉。

"main" #1 prio=5 os_prio=0 tid=0x0000000001c1e000 nid=0x1c78 in Object.wait() [0
x000000000272f000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
-waiting on <0x00000000d6f7a970> (a java.lang.Integer)
at Test.timedWaiting(Test.java:25)
-locked <0x00000000d6f7a970> (a java.lang.Integer)
at Test.main(Test.java:18)

Locked ownable synchronizers:
-None

4) 讓線程處于WAITING狀態(tài)狀態(tài)

public static void main(String[] args) {
  printPId();//打印進程id

  waiting();//模擬waiting狀態(tài)方法
}

public static void waiting() {
  Integer lock = 0;
  synchronized (lock) {
      try {
          lock.wait();
      } catch (Exception e) {
          e.printStackTrace();
      }
  }
}

public static void printPId() {
  String name = ManagementFactory.getRuntimeMXBean().getName();
  System.out.println(name.split("@")[0]);
}

無超時的等待烹植,必須等待lock.notify()或lock.notifyAll()或接收到interrupt信號才能退出等待狀態(tài)愕贡。同理,ReentrantLock.lock()的無參方法調(diào)用墩虹,也會使線程狀態(tài)變成WAITING憨琳。

"main" #1 prio=5 os_prio=0 tid=0x00000000024ce000 nid=0x2b14 in Object.wait() [0
x00000000025ef000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
-waiting on <0x00000000d6f7a970> (a java.lang.Integer)
at java.lang.Object.wait(Unknown Source)
at Test.waiting(Test.java:27)
-locked <0x00000000d6f7a970> (a java.lang.Integer)
at Test.main(Test.java:20)

Locked ownable synchronizers:
-None

掌握各個線程的狀態(tài)和信息,將無往而不利~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末尖坤,一起剝皮案震驚了整個濱河市慢味,隨后出現(xiàn)的幾起案子墅冷,更是在濱河造成了極大的恐慌,老刑警劉巖寞忿,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件腔彰,死亡現(xiàn)場離奇詭異,居然都是意外死亡搓逾,警方通過查閱死者的電腦和手機杯拐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來朗兵,“玉大人,你說我怎么就攤上這事寸爆∽抢簦” “怎么了?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵歌憨,是天一觀的道長墩衙。 經(jīng)常有香客問我漆改,道長,這世上最難降的妖魔是什么挫剑? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任樊破,我火速辦了婚禮,結(jié)果婚禮上奔滑,老公的妹妹穿的比我還像新娘顺少。我一直安慰自己,他們只是感情好梅猿,可當我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布腕窥。 她就那樣靜靜地躺著,像睡著了一般癞松。 火紅的嫁衣襯著肌膚如雪入蛆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天枫甲,我揣著相機與錄音扼褪,去河邊找鬼话浇。 笑死,一個胖子當著我的面吹牛幔崖,可吹牛的內(nèi)容都是我干的赏寇。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼自娩,長吁一口氣:“原來是場噩夢啊……” “哼渠退!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起动漾,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤荠锭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后删豺,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體愧怜,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡拥坛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年尘分,在試婚紗的時候發(fā)現(xiàn)自己被綠了培愁。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缓窜。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖私股,靈堂內(nèi)的尸體忽然破棺而出恩掷,到底是詐尸還是另有隱情,我是刑警寧澤旦签,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布寸宏,位于F島的核電站,受9級特大地震影響羔巢,放射性物質(zhì)發(fā)生泄漏罩阵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一幽钢、第九天 我趴在偏房一處隱蔽的房頂上張望傅是。 院中可真熱鬧,春花似錦帽驯、人聲如沸书闸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蛉威。三九已至走哺,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間择示,已是汗流浹背晒旅。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留谈秫,地道東北人鱼鼓。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓迄本,卻偏偏與公主長得像,于是被迫代替她去往敵國和親嘉赎。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 背景 10月2號凌晨12:08收到報警,所有請求失敗靶橱,處于完全不可用狀態(tài) 應(yīng)用服務(wù)器共四臺resin,resin之...
    AGIHunt閱讀 22,019評論 6 16
  • Java程序員進階三條必經(jīng)之路:數(shù)據(jù)庫、虛擬機谒拴、異步通信。 前言 入門JVM垃圾回收機制后炭序,接下來可以學(xué)習(xí)性能調(diào)優(yōu)...
    MountainKing閱讀 23,131評論 1 35
  • ANR問題辜纲,相信是每位開發(fā)日常都會遇到的問題,對于這類問題的分析耕腾,按照官方的推薦扫俺,或網(wǎng)絡(luò)博客的總結(jié)思路能解決一定的...
    tiger桂閱讀 17,913評論 5 28
  • 參考自 http://techblog.youdao.com/?p=961 在分析具體故障,先介紹一下幾種常用的工...
    抓兔子的貓閱讀 5,955評論 1 27
  • 錯過羹呵,是個非常浪漫的詞語疗琉。就像缺陷美一樣,人們往往念念不忘的是那份遺憾涛癌。 大二的時候送火,我喜歡上隔壁班的一個女生。 ...
    月海樓閱讀 392評論 0 0