centos中bash占用cpu,linux下如何定位CPU占用高的进程的问题点
一、Top+pstack+gdb的組合拳
閑言少述,先直接上操作實例,再做原理講解。
1.1 用top命令找到最占CPU的進程
>top
PID USER? ? ? PR? NI? VIRT? RES? SHR S %CPU %MEM? ? TIME+? COMMAND
22688 root? ? ? 20? ?0 1842m 136m? 13m S 110.0? 0.9? ?1568:44 test-program
1.2 使用pstack跟蹤進程棧
此命令可顯示每個進程的棧跟蹤。
pstack 命令必須由相應(yīng)進程的屬主或 root 運行。可以使用 pstack 來確定進程掛起的位置。
此命令允許使用的唯一選項是要檢查的進程的 PID。
這個命令在排查進程問題時非常有用,
比如我們發(fā)現(xiàn)一個服務(wù)一直處于work狀態(tài)(如假死狀態(tài),好似死循環(huán)),
使用這個命令就能輕松定位問題所在;
可以在一段時間內(nèi),多執(zhí)行幾次pstack,若發(fā)現(xiàn)代碼棧總是停在同一個位置,
那個位置就需要重點關(guān)注,很可能就是出問題的地方;
>pstack 22688
Thread 44 (Thread 0x7fa97035f700 (LWP 22689)):
#0? 0x00007fa96f386a00 in sem_wait () from /lib64/libpthread.so.0
#1? 0x0000000000dfef12 in uv_sem_wait ()
#2? 0x0000000000d67832 in node::DebugSignalThreadMain(void*) ()
#3? 0x00007fa96f380aa1 in start_thread () from /lib64/libpthread.so.0
#4? 0x00007fa96f0cdaad in clone () from /lib64/libc.so.6
Thread 43 (Thread 0x7fa96efe4700 (LWP 22690)):
#0? 0x00007fa96f386a00 in sem_wait () from /lib64/libpthread.so.0
#1? 0x0000000000e08a38 in v8::base::Semaphore::Wait() ()
#2? 0x0000000000dddde9 in v8::platform::TaskQueue::GetNext() ()
#3? 0x0000000000dddf3c in v8::platform::WorkerThread::Run() ()
#4? 0x0000000000e099c0 in v8::base::ThreadEntry(void*) ()
#5? 0x00007fa96f380aa1 in start_thread () from /lib64/libpthread.so.0
#6? 0x00007fa96f0cdaad in clone () from /lib64/libc.so.6
Thread 42 (Thread 0x7fa96e5e3700 (LWP 22691)):
#0? 0x00007fa96f386a00 in sem_wait () from /lib64/libpthread.so.0
#1? 0x0000000000e08a38 in v8::base::Semaphore::Wait() ()
#2? 0x0000000000dddde9 in v8::platform::TaskQueue::GetNext() ()
#3? 0x0000000000dddf3c in v8::platform::WorkerThread::Run() ()
#4? 0x0000000000e099c0 in v8::base::ThreadEntry(void*) ()
#5? 0x00007fa96f380aa1 in start_thread () from /lib64/libpthread.so.0
#6? 0x00007fa96f0cdaad in clone () from /lib64/libc.so.6
Thread 41 (Thread 0x7fa96dbe2700 (LWP 22692)):
#0? 0x00007fa96f386a00 in sem_wait () from /lib64/libpthread.so.0
#1? 0x0000000000e08a38 in v8::base::Semaphore::Wait() ()
#2? 0x0000000000dddde9 in v8::platform::TaskQueue::GetNext() ()
#3? 0x0000000000dddf3c in v8::platform::WorkerThread::Run() ()
#4? 0x0000000000e099c0 in v8::base::ThreadEntry(void*) ()
#5? 0x00007fa96f380aa1 in start_thread () from /lib64/libpthread.so.0
#6? 0x00007fa96f0cdaad in clone () from /lib64/libc.so.6
使用top命令查看指定進程最耗CPU的線程,
下面找到的線程號為 22970.
>top -H -p 22688
PID USER? ? ? PR? NI? VIRT? RES? SHR S %CPU %MEM? ? TIME+? COMMAND
22970 root? ? ? 20? ?0 1842m 136m? 13m R? 100.2 0.9 1423:40 test-program
NOTE:
這里的PID是系統(tǒng)給每個線程分配的唯一的線程號,不是進程號,但名稱也是PID。
這兩者的具體區(qū)別可見:
《linux中pid,tid, 以及 真實pid的關(guān)系》
http://blog.csdn.net/u012398613/article/details/52183708
使用線程號PID反查其對應(yīng)的線程號。
如下就找到了 線程 22970對應(yīng)的線程10
>pstack 22688 | grep 22970
Thread 10 (Thread 0x7fa92f5fe700 (LWP 22970)):
使用VIM查看進程快照,定位到具體的線程,并查看其調(diào)用堆棧;
>pstack 22688 | vim -
Thread 10 (Thread 0x7fa92f5fe700 (LWP 22970)):
#0? 0x00007fa96f02a04f in vfprintf () from /lib64/libc.so.6
#1? 0x00007fa96f054712 in vsnprintf () from /lib64/libc.so.6
#2? 0x00007fa967b3861c in lv_write_log () from /opt/test-program
#3? 0x00007fa967b26173 in LvJbuf::pjmedia_jbuf_put_rtp_pkg(pjmedia_rtp_decoded_pkg const*, int*) () from /opt/test-program
#4? 0x00007fa96782409f in livesrv::LvAudio::on_rtp_stream(void*, unsigned int, unsigned int) () from /opt/test-program
#5? 0x00007fa96781fc87 in livesrv::LvMedia::recv_media(void*, unsigned int, unsigned char, unsigned int) () from /opt/test-program
#6? 0x00007fa967818c7f in livesrv::LvChannel::do_recv_media_check_thread2() () from /opt/test-program/node_modules/livesource/Debug/linux/livesource.node
#7? 0x00007fa967814699 in recv_media_process2(void*) () from /opt/test-program
#8? 0x00007fa96f380aa1 in start_thread () from /lib64/libpthread.so.0
#9? 0x00007fa96f0cdaad in clone () from /lib64/libc.so.6
上面的操作基本定位到了具體線程和大概的函數(shù),
如果想查看具體的原因,如現(xiàn)場的函數(shù)中變量等的數(shù)值等,就要使用的GDB的實時調(diào)試功能。
1.3 使用gdb調(diào)試實時進程
>gdb attach 22688
:thread 10
:bt
:frame x
:p xxx
二、top用法
2.1 top:動態(tài)觀察程序的變化
[root@linux ~]# top [-d] | top [-bnp]
參數(shù):
-d :后面可以接秒數(shù),就是整個程序畫面更新的秒數(shù)。預設(shè)是 5 秒;
-b :以批次的方式執(zhí)行 top ,還有更多的參數(shù)可以使用喔!
通常會搭配數(shù)據(jù)流重導向來將批次的結(jié)果輸出成為檔案。
-n :與 -b 搭配,意義是,需要進行幾次 top 的輸出結(jié)果。
-p :指定某些個 PID 來進行觀察監(jiān)測而已。
在 top 執(zhí)行過程當中可以使用的按鍵指令:
? :顯示在 top 當中可以輸入的按鍵指令;
P :以 CPU 的使用資源排序顯示;
M :以 Memory 的使用資源排序顯示;
N :以 PID 來排序喔!
T :由該 Process 使用的 CPU 時間累積 (TIME+) 排序。
k :給予某個 PID 一個訊號 (signal)
r :給予某個 PID 重新制訂一個 nice 值。
2.2 top 也是個挺不錯的程序觀察工具!
不同于 ps 是靜態(tài)的結(jié)果輸出, top 這個程序可以持續(xù)的監(jiān)測 (monitor) 整個系統(tǒng)的程序工作狀態(tài),
例如上面的范例一所示啊! 在預設(shè)的情況下,每次更新程序資源的時間為 5 秒,
不過,可以使用 -d 來進行修改。
top 主要分為兩個畫面,上面的畫面為整個系統(tǒng)的資源使用狀態(tài),基本上總共有六行, 顯示的內(nèi)容依序是:
? 第一行:顯示系統(tǒng)已啟動的時間、目前上線人數(shù)、系統(tǒng)整體的負載(load)。
比較需要注意的是系統(tǒng)的負載,三個數(shù)據(jù)分別代表 1, 5, 10 分鐘的平均負載。
一般來說,這個負載值應(yīng)該不太可能超過 1 才對,除非您的系統(tǒng)很忙碌。
如果持續(xù)高于 5 的話,那么.....仔細的看看到底是那個程序在影響整體系統(tǒng)吧!
? 第二行:顯示的是目前的觀察程序數(shù)量,
比較需要注意的是最后的 zombie 那個數(shù)值,如果不是 0 ,
嘿嘿!好好看看到底是那個 process 變成疆尸了吧?!
? 第三行:顯示的是 CPU 的整體負載,每個項目可使用 ? 查閱。
需要觀察的是 id (idle) 的數(shù)值,一般來說,他應(yīng)該要接近 100% 才好,表示系統(tǒng)很少資源被使用啊! ^_^。
? 第四行與第五行:表示目前的物理內(nèi)存與虛擬內(nèi)存 (Mem/Swap) 的使用情況。
? 第六行:這個是當在 top 程序當中輸入指令時,顯示狀態(tài)的地方。 例如范例四就是一個簡單的使用例子。
至于 top 底下的畫面,則是每個 process 使用的資源情況。比較需要注意的是:
? PID? ?:每個 process 的 ID 啦!
? USER? :該 process 所屬的使用者;
? PR? ? :Priority 的簡寫,程序的優(yōu)先執(zhí)行順序,越小越早被執(zhí)行;
? NI? ? :Nice 的簡寫,與 Priority 有關(guān),也是越小越早被執(zhí)行;
? %CPU? :CPU 的使用率;
? %MEM? :內(nèi)存的使用率;
? TIME+ :CPU 使用時間的累加;
一般來說,如果鳥哥想要找出最損耗 CPU 資源的那個程序時,大多使用的就是 top 這支程序啦!
然后強制以 CPU 使用資源來排序 (在 top 當中按下 P 即可), 就可以很快的知道啦! ^_^。
三、pstack用法
此命令可顯示每個進程的棧跟蹤。
pstack 命令必須由相應(yīng)進程的屬主或 root 運行。可以使用 pstack 來確定進程掛起的位置。
此命令允許使用的唯一選項是要檢查的進程的 PID。請參見 proc(1) 手冊頁。
這個命令在排查進程問題時非常有用,比如我們發(fā)現(xiàn)一個服務(wù)一直處于work狀態(tài)(如假死狀態(tài),好似死循環(huán)),
使用這個命令就能輕松定位問題所在;
可以在一段時間內(nèi),多執(zhí)行幾次pstack,
若發(fā)現(xiàn)代碼棧總是停在同一個位置,那個位置就需要重點關(guān)注,很可能就是出問題的地方;
示例:查看bash程序進程棧:
/opt/app/tdev1$ps -fe| grep bash
tdev1? ?7013? 7012? 0 19:42 pts/1? ? 00:00:00 -bash
tdev1? 11402 11401? 0 20:31 pts/2? ? 00:00:00 -bash
tdev1? 11474 11402? 0 20:32 pts/2? ? 00:00:00 grep bash
/opt/app/tdev1$pstack 7013
#0? 0x00000039958c5620 in __read_nocancel () from /lib64/libc.so.6
#1? 0x000000000047dafe in rl_getc ()
#2? 0x000000000047def6 in rl_read_key ()
#3? 0x000000000046d0f5 in readline_internal_char ()
#4? 0x000000000046d4e5 in readline ()
#5? 0x00000000004213cf in ?? ()
#6? 0x000000000041d685 in ?? ()
#7? 0x000000000041e89e in ?? ()
#8? 0x00000000004218dc in yyparse ()
#9? 0x000000000041b507 in parse_command ()
#10 0x000000000041b5c6 in read_command ()
#11 0x000000000041b74e in reader_loop ()
#12 0x000000000041b2aa in main ()
四、GDB調(diào)試運行中程序的方法
4.1 多線程調(diào)試
多線程調(diào)試最重要就是下面幾個命令:
1. 查看當前進程的線程。
info thread
2. 切換調(diào)試的線程為指定ID的線程。
thread 3. 在file.c文件第100行處為所有經(jīng)過這里的線程設(shè)置斷點。
break file.c:100 thread all
4. 線程開關(guān)
在使用step或者continue命令調(diào)試當前被調(diào)試線程的時候,其他線程也是同時執(zhí)行的,
怎么只讓被調(diào)試程序執(zhí)行呢?通過這個命令就可以實現(xiàn)這個需求。
set scheduler-locking off|on|step,
. off? ? 不鎖定任何線程,也就是所有線程都執(zhí)行,這是默認值。
. on? ? ?只有當前被調(diào)試程序會執(zhí)行。
. step? ?在單步的時候,除了next過一個函數(shù)的情況
(熟悉情況的人可能知道,這其實是一個設(shè)置斷點然后continue的行為)以外,
只有當前線程會執(zhí)行。
4.2 調(diào)試宏
在GDB下,我們無法print宏定義,因為宏是預編譯的。
但是我們還是有辦法來調(diào)試宏,這個需要GCC的配合。
在GCC編譯程序的時候,加上-ggdb3參數(shù),這樣,你就可以調(diào)試宏了。
另外,你可以使用下述的GDB的宏調(diào)試命令 來查看相關(guān)的宏。
info macro – 你可以查看這個宏在哪些文件里被引用了,以及宏定義是什么樣的。
macro – 你可以查看宏展開的樣子。
1、首先獲得程序的PID
ps -ef | grep xxxxx
2、進入調(diào)試程序
gdb attach PID
3、gcore命令生成CORE文件
4、進程信息可以用info? proc顯示
5、寄存器信息可以用info reg顯示
閱讀(10975) | 評論(0) | 轉(zhuǎn)發(fā)(0) |
總結(jié)
以上是生活随笔為你收集整理的centos中bash占用cpu,linux下如何定位CPU占用高的进程的问题点的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: arduino读取matlab串口,Ma
- 下一篇: 银行卡断了补办卡号会变吗