pstack
是一個shell腳本,用於打印正在運行的進程的棧跟蹤信息,它實際上是gstack
的一個鏈接,而gstack本身是基於gdb封裝的shell腳本.。此命令可顯示每個進程的棧跟蹤。pstack 命令必須由相應進程的屬主或 root 運行。可以使用 pstack 來確定進程掛起的位置。此命令允許使用的唯一選項是要檢查的進程的 PID。
與jstack功相比, 它能對潛在的死鎖予以提示, 而pstack只提供了線索, 需要gdb進一步的確定。
pstack
是gdb的一部分,如果系統沒有pstack命令,使用yum搜索安裝gdb
即可。
這個命令在排查進程問題時非常有用,比如我們發現一個服務一直處於work狀態(如假死狀態,好似死循環),使用這個命令就能輕松定位問題所在;可以在一段時間內,多執行幾次pstack,若發現代碼棧總是停在同一個位置,那個位置就需要重點關注,很可能就是出問題的地方;
示例1:查看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 ()
或者類似這樣執行
$ sudo pstack $(pgrep -uroot php-fpm) [sudo] password for guanyy: #0 0x000000380d8e86f3 in __epoll_wait_nocancel () from /lib64/libc.so.6 #1 0x00000000007ec4a4 in fpm_event_epoll_wait () #2 0x00000000007e1517 in fpm_event_loop () #3 0x00000000007dc887 in fpm_run () #4 0x00000000007e3bd8 in main ()
實例2:ps -eLo pid,lwp,pcpu |grep pid
利用一個最簡單的命令就能夠定位到哪段程序可能存在性能問題:獲取進程ID,通過pstack命令查看里邊的各個線程id以及對應的線程現在正在做什么事情,分析多組數據就可以獲得哪些線程里有慢操作影響了服務器的性能,從而得到解決方案
本地線程ID
"NativeThread ID"所指的本地線程是指該java虛擬機所對應的虛擬機中的本地線程,java代碼是依附於java虛擬機的本地線程執行的,當啟動一個線程時,是創建一個native本地線程,本地線程才是真實的線程實體,為了更加深入理解本地線程和java線程的關系,可以通過以下方式將java虛擬機的本地線程打印出來:
1、試用ps -ef|grep java 獲得java進行id
2、試用pstack<java pid> 獲得java虛擬機本地線程的堆棧
從操作系統打印出來的虛擬機的本地線程看,本地線程數量和java線程數量是相同的,說明二者是一一對應的關系。
那么本地線程號如何與java線程堆棧文件對應起來呢,每一個線程都有tid,nid的屬性。----dump文件中每個線程的nid值。
