Linux 多線程調試(內存占用、死循環、CPU占用率高……)


你的軟件在某個時刻停止服務,CPU占用達到100%+,這種問題一個可能的原因是產生了死循環,假設程序某處存在潛在的死循環,並在某種條件下會引發,本文以一個示例來定位出現死循環的位置。
當程序某處存在死循環,通常定位問題及縮小范圍的方法是,在可疑的代碼處加log,或者注釋掉可疑代碼,這對於容易重現問題的程序來說還好,但對於“偶爾”才會產生問題程序卻很難調試,因為我們很難重現程序故障。本文所述的調試過程正是在這種情況下,假設問題已經出現,我們要求環境保護現場,即出問題的程序還在運行中。

1.我們首先要知道是哪個線程出了問題:
首先查一下出問題進程的pid,例如

ovtsvn@ovtsvn: ~/MASS4/src/icdn/src$ ps  - ef  |  grep icdn
ovtsvn    11065       1   50   11 : 57   ?          00 : 00 : 07  . / icdn
ovtsvn    11076   10971    0   11 : 57  pts / 2      00 : 00 : 00  grep
ovtsvn@ovtsvn: ~/ MASS4 / src / icdn / src$
ovtsvn@ovtsvn: ~/ MASS4 / src / icdn / src$ 

然后top命令查看線程信息:
top -H -p 11065

PID USER      PR  NI  VIRT  RES  SHR S  % CPU  % MEM    TIME +   COMMAND                                                                
11073  ovtsvn     25     0   325m  3980   2236  R   100    0.4     1 : 40.84  icdn                                                                   
11065  ovtsvn     18     0   325m  3980   2236  S     0    0.4     0 : 00.01  icdn                                                                   
11066  ovtsvn     18     0   325m  3980   2236  S     0    0.4     0 : 00.00  icdn                                                                   
11067  ovtsvn     15     0   325m  3980   2236  S     0    0.4     0 : 00.00  icdn                                                                   
11068  ovtsvn     15     0   325m  3980   2236  S     0    0.4     0 : 00.00  icdn                                                                   
11069 ovtsvn 18 0 325m 3980 2236 S 0 0.4 0 : 00.00 icdn
11070 ovtsvn 18 0 325m 3980 2236 S 0 0.4 0 : 00.00 icdn
11071 ovtsvn 22 0 325m 3980 2236 S 0 0.4 0 : 00.00 icdn
11072 ovtsvn 15 0 325m 3980 2236 R 0 0.4 0 : 00.00 icdn
 

從上面可以看出,出問題線程PID為11073

2.接下來,我們用gdb來attach目標進程
執行: gdb icdn 11065
在gdb中,列出線程狀態:

(gdb) info threads   
9  Thread  47056948181264  (LWP  11066 )   0x00002acc4a3dec91   in  nanosleep () from  / lib / libc.so. 6   
8  Thread  47056956573968  (LWP  11067 )   0x00002acc4a406fc2   in  select () from  / lib / libc.so. 6   
7  Thread  47056964966672  (LWP  11068 )   0x00002acc4a3dec91   in  nanosleep () from  / lib / libc.so. 6  
  6  Thread  47056973359376  (LWP  11069 )   0x00002acc4a3dec91   in  nanosleep () from  / lib / libc.so. 6   
5  Thread  47056981752080  (LWP  11070 )   0x00002acc4a3dec91   in  nanosleep () from  / lib / libc.so. 6   
4  Thread  47056990144784  (LWP  11071 )   0x00002acc4a40e63c   in  recvfrom () from  / lib / libc.so. 6   
3  Thread  47057194060048  (LWP  11072 )   0x00002acc4a406fc2   in  select () from  / lib / libc.so. 6   
2  Thread  47057226893584  (LWP  11073 )  CSendFile::SendFile ( this = 0x2acc5d4aff40 , pathname = @ 0x2acc5d4afee0 )     at .. / src / csendfile.cpp: 101   
1  Thread  47056939784832  (LWP  11065 )   0x00002acc4a3dec91   in  nanosleep () from  / lib / libc.so. 6 (gdb) 


gdb已經列出了各線程正在執行的函數,我們需要更多信息,記住11073對應的行首標號,這是gdb為線程分配的id,這里為2,然后執行切換:

(gdb) thread  2
[Switching to thread  2  (Thread  47057226893584  (LWP  11073 ))]# 0   CSendFile::SendFile ( this = 0x2acc5d4aff40 , pathname = @ 0x2acc5d4afee0 )     at .. / src / csendfile.cpp: 101 101               while ( 1 )
(gdb) 

bt一下:

(gdb) bt
# 0   CSendFile::SendFile ( this = 0x2acc5d4aff40 , pathname = @ 0x2acc5d4afee0 ) at .. / src / csendfile.cpp: 101
# 1    0x000000000040592e   in  CIcdn::TaskThread (pParam = 0x7fff617eafe0 ) at .. / src / cicdn.cpp: 128
# 2    0x00002acc4a90b73a   in  start_thread () from  / lib / libpthread.so. 0
# 3    0x00002acc4a40d6dd   in  clone () from  / lib / libc.so. 6
# 4    0x0000000000000000   in   ??  ()


來看一下101行的代碼:

(gdb) l
96       }
97
98        int  CSendFile::SendFile( const   string &  pathname)
99        {
100             int n;
101             while(1)
102             {
103                     n++;
104             }
105             //read file and send 

現在我們定位到了出問題的代碼位置,這里的循環只用來演示的。 
最后別忘了detach()

調試完指定進程后,可以運行detach命令來讓GDB釋放該進程,該進程得以繼續運行。當回車時,detach不會重復。當執行完detach后,進程和GDB不再相關,GDB可以attach其他進程。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM