標籤:http failure 修改 核心 ons 基本 程式員 三次 命令
這裡我們主要介紹進程的狀態,進程的狀態可以通過/proc/PID/status來查看,也可以通過/proc/PID/stat來查看.如果說到工具大家用的最多的ps也可以看到進程的資訊.這裡我們通過/proc/PID/status來分析進程的資訊.在2.6.18之後的核心,多了capibilty/cpusets等資訊. 查看進程狀態資訊如下:more status Name: rsyslogdState: S (sleeping)Tgid: 987Pid: 987PPid: 1TracerPid: 0Uid: 0 0 0 0Gid: 0 0 0 0Utrace: 0FDSize: 32Groups:VmPeak: 36528 kBVmSize: 36528 kBVmLck: 0 kBVmHWM: 1432 kBVmRSS: 1420 kBVmData: 33980 kBVmStk: 88 kBVmExe: 320 kBVmLib: 2044 kBVmPTE: 56 kBVmSwap: 0 kBThreads: 3SigQ: 1/7954SigPnd: 0000000000000000ShdPnd: 0000000000000000SigBlk: 0000000000000000SigIgn: 0000000001001206SigCgt: 0000000180014c21CapInh: 0000000000000000CapPrm: ffffffffffffffffCapEff: ffffffffffffffffCapBnd: ffffffffffffffffCpus_allowed: 3Cpus_allowed_list: 0-1Mems_allowed: 1Mems_allowed_list: 0voluntary_ctxt_switches: 1nonvoluntary_ctxt_switches: 0 Name: rsyslogd解釋:進程名 State: S (sleeping)解釋:進程的狀態我們前文已經做了很詳細的分析,各進程的狀態代表的意義如下:R (running)", "S (sleeping)", "D (disk sleep)", "T (stopped)", "T(tracing stop)", "Z (zombie)", or "X (dead)" Tgid: 987解釋:Tgid是線程組的ID,一個線程一定屬於一個線程組(進程組). Pid: 987解釋:這個是進程的ID,更準確的說應該是線程的ID.例如:UID PID PPID LWP C NLWP STIME TTY TIME CMDroot 987 1 987 0 3 00:18 ? 00:00:00 /sbin/rsyslogd -c 4root 987 1 989 0 3 00:18 ? 00:00:00 /sbin/rsyslogd -c 4root 987 1 990 0 3 00:18 ? 00:00:00 /sbin/rsyslogd -c 4注:/proc/pid/status中的Pid就是ps命令的LWP列輸出,PID一列其實是進程組,而LWP是輕量級進程,也就是線程,因為所有的進程必須一個線程,那就是它自己. PPid: 1解釋:當前進程的父進程 TracerPid: 0解釋:跟蹤當前進程的進程ID,如果是0,表示沒有跟蹤.例如:用strace跟蹤top程式strace top 查看top進程ps -axjfPPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 2491 2500 2500 2491 pts/2 2500 S+ 0 0:00 \_ strace top 2500 2501 2500 2491 pts/2 2500 S+ 0 0:00 \_ top 查看top進程的TracerPid位cat /proc/2501/statstat statm status test1:/proc/2431# cat /proc/2501/status Name: topState: S (sleeping)Tgid: 2501Pid: 2501PPid: 2500TracerPid: 2500 Uid: 0 0 0 0Gid: 0 0 0 0解釋:第一列數字(RUID):實際使用者ID,指的是進程執行者是誰.第二列數字(EUID):有效使用者ID,指進程執行時對檔案的存取權限.第三列數字(SUID):儲存設定使用者ID,作為effective user ID的副本,在執行exec調用時後能重新恢複原來的effectiv user ID.第四列數字(FSUID):目前進程的檔案系統的使用者識別碼.一般情況下,檔案系統的使用者識別碼(fsuid)與有效使用者識別碼(euid)是相同的.這裡重點說明RUID和EUID,我們用test使用者啟動top,如下:終端1)su - testtop 查看該進程的EUID和RUID,如下:終端2)cat /proc/`pgrep top|grep -v grep`/status前面略Uid: 1002 1002 1002 1002Gid: 1003 1003 1003 1003後面略 注:這裡我們看到進程的RUID和EUID都變成了1002. 我們將程式top加上setuid許可權,如下:chmod +s /usr/bin/top 重新運行top程式,並查看它的RUID和EUID,如下:cat /proc/`pgrep top|grep -v grep`/status前面略Uid: 1002 0 0 0Gid: 1003 0 0 0後面略 注:我們看到RUID還是1002,說明程式是由test使用者(UID=1002)啟動的,而程式設定了setuid,那麼在程式運行時是用程式的owner許可權來運行程式,而不是啟動的使用者權限.由於top的owner是root,那麼它的EUID是0. FDSize: 32解釋:FDSize是當前分配的檔案描述符,這個值不是當前進程使用檔案描述符的上限.我們看到這裡是32,但實際並沒有分配32個檔案,如下:ls -l /proc/`pgrep rsyslogd|grep -v grep`/fd total 0lrwx------ 1 root root 64 2011-04-20 20:03 0 -> socket:[5741]l-wx------ 1 root root 64 2011-04-20 20:03 1 -> /var/log/auth.logl-wx------ 1 root root 64 2011-04-20 20:03 10 -> /var/log/mail.errl-wx------ 1 root root 64 2011-04-20 20:03 11 -> /var/log/news/news.critl-wx------ 1 root root 64 2011-04-20 20:03 12 -> /var/log/news/news.errl-wx------ 1 root root 64 2011-04-20 20:03 13 -> /var/log/news/news.noticel-wx------ 1 root root 64 2011-04-20 20:03 14 -> /var/log/debugl-wx------ 1 root root 64 2011-04-20 20:03 15 -> /var/log/messageslrwx------ 1 root root 64 2011-04-20 20:03 16 -> /dev/xconsolelr-x------ 1 root root 64 2011-04-20 20:03 17 -> /proc/kmsgl-wx------ 1 root root 64 2011-04-20 20:03 2 -> /var/log/syslogl-wx------ 1 root root 64 2011-04-20 20:03 3 -> /var/log/daemon.logl-wx------ 1 root root 64 2011-04-20 20:03 4 -> /var/log/kern.logl-wx------ 1 root root 64 2011-04-20 20:03 5 -> /var/log/lpr.logl-wx------ 1 root root 64 2011-04-20 20:03 6 -> /var/log/mail.logl-wx------ 1 root root 64 2011-04-20 20:03 7 -> /var/log/user.logl-wx------ 1 root root 64 2011-04-20 20:03 8 -> /var/log/mail.infol-wx------ 1 root root 64 2011-04-20 20:03 9 -> /var/log/mail.warn我們看到這裡只用到了18個檔案描述符.而如果超過32個檔案描述符,將以32進行遞增,如果是64位系統,將以64進行遞增.FDSize這個值不會減少,如果我們程式開啟了300個檔案,並不會因為關閉檔案,而減少FDSize這個值. Groups: 0解釋:這裡的groups表示啟動這個進程的使用者所在的組.我們當前的使用者test,現在在兩個組(1000,2000)裡面,如下:iduid=1002(test) gid=1002(nagcmd) groups=1000(chenkuo),1002(nagcmd) 用test使用者啟動top程式,並查看它的groups,如下:終端1top 終端2cat /proc/`pgrep top|grep -v grep`/status截取資訊如下:Groups: 1000 1002 VmPeak: 36528 kB解釋:這裡的VmPeak代表當前進程運行過程中佔用記憶體的峰值.我們用下面的程式申請記憶體,然後釋放記憶體,最後通pause()函數中止程式的運行,程式源碼如下: #include#include#include#include intmain (int argc, char *argv[]){ if (argc != 2) exit (0); size_t mb = strtoul(argv[1],NULL,0); size_t nbytes = mb * 0x100000; char *ptr = (char *) malloc(nbytes); if (ptr == NULL){ perror("malloc"); exit (EXIT_FAILURE); } printf("allocated %d mb\n", mb); free(ptr); pause(); return 0;} gcc callmem.c -o callmem ./callmem 10allocated 10 mb 終端2我們開啟status檔案,查看VmPeak值,如下:cat /proc/`pgrep callmem|grep -v grep`/statusName: callmemState: S (sleeping)Tgid: 2930Pid: 2930PPid: 2831TracerPid: 0Uid: 1002 1002 1002 1002Gid: 1002 1002 1002 1002FDSize: 256Groups: 1000 1002 VmPeak: 11852 kBVmSize: 1608 kBVmLck: 0 kBVmHWM: 396 kBVmRSS: 396 kBVmData: 28 kBVmStk: 84 kBVmExe: 4 kBVmLib: 1468 kBVmPTE: 12 kB下面略注:我們看到程式申請了10240kb(10MB)的記憶體,VmPeak的值為11852kb,為什麼不是10MB呢,因為除了我們申請的記憶體外,程式還會為載入動態連結程式庫而佔用記憶體. VmSize: 36528 kB解釋:VmSize代表進程現在正在佔用的記憶體這個值與pmap pid的值基本一致,如果略有不同,可能是記憶體裂縫所造成的. VmLck: 0 kB解釋:VmLck代表進程已經鎖住的實體記憶體的大小.鎖住的實體記憶體不能交換到硬碟.我們用下面的程式進行測試,如下:#include#include int main(int argc, char* argv[]){ char array[2048]; if (mlock((const void *)array, sizeof(array)) == -1) { perror("mlock: "); return -1; } printf("success to lock stack mem at: %p, len=%zd\n", array, sizeof(array)); sleep(60); if (munlock((const void *)array, sizeof(array)) == -1) { perror("munlock: "); return -1; } printf("success to unlock stack mem at: %p, len=%zd\n", array, sizeof(array)); return 0;} 編譯後運行:gcc memlock.c -o memlock 我們這裡將2048個位元組的數組地址空間鎖定到了實體記憶體中.接下來我們看下Vmlck值的變化,如下:cat /proc/`pgrep memlock|grep -v grep`/statusName: memlockState: S (sleeping)Tgid: 3249Pid: 3249PPid: 3139TracerPid: 0Uid: 0 0 0 0Gid: 0 0 0 0FDSize: 256Groups: 0 VmPeak: 1624 kBVmSize: 1608 kBVmLck: 4 kBVmHWM: 356 kBVmRSS: 356 kBVmData: 28 kBVmStk: 84 kBVmExe: 4 kBVmLib: 1468 kBVmPTE: 16 kB 我們看到Vmlck的值為4Kb,這是因為分配的最少單位是4KB,以後每次遞增都是4KB的整數倍. VmHWM: 1432 kBVmRSS: 1420 kB解釋:VmHWM是程式得到分配到實體記憶體的峰值.VmRSS是程式現在使用的實體記憶體.我們用下面的程式進行測試,如下:#include#include#include#include intmain (int argc, char *argv[]){ if (argc != 2) exit (0); size_t mb = strtoul(argv[1],NULL,0); size_t nbytes = mb * 0x100000; char *ptr = (char *) malloc(nbytes); if (ptr == NULL){ perror("malloc"); exit (EXIT_FAILURE); } size_t i; const size_t stride = sysconf(_SC_PAGE_SIZE); for (i = 0;i < nbytes; i+= stride) { ptr[i] = 0; } printf("allocated %d mb\n", mb); pause(); return 0;}編譯:gcc callmem.c -o test注意這個程式在每頁都修改一個位元組的資料,導致系統必須為它分配佔用實體記憶體. 首先我們查看當前的記憶體,如下:free -m total used free shared buffers cachedMem: 503 18 484 0 0 5-/+ buffers/cache: 12 490Swap: 7632 7 7624 我們看到當前有490MB的空閑實體記憶體.運行callmem分配450MB的實體記憶體,如下:./test 450&[1] 2402allocated 450 mb 我們查看進程的VmHWM和VmRSS,如下:cat /proc/`pgrep test`/status略VmHWM: 461208 kBVmRSS: 461208 kB略我們看到此時VmHWM和VmRSS是一樣的,表示佔用了460MB左右的實體記憶體(因為它會用到動態連結程式庫等). 下面我們查看當前的記憶體使用量情況,如下:free -m total used free shared buffers cachedMem: 503 470 33 0 0 6-/+ buffers/cache: 463 40Swap: 7632 7 7625 我們看到還有40MB空閑實體記憶體.我們下面再申請100MB的記憶體,此時系統會通過實體記憶體和SWAP的置換操作,把第1次啟動並執行test進程所佔用的實體記憶體置換到SWAP,把空出來的實體記憶體分配給第2次啟動並執行程式,如下:mv test test1./test1 100&[1] 2419allocated 100 mb 再次查看test進程所佔用的實體記憶體,如下:cat /proc/`pgrep test`/status略VmHWM: 461208 kBVmRSS: 386704 kB略 最後我們看到VmHWM沒有變化,因為它表示的是該進程所佔用實體記憶體的峰值,不會因為把記憶體置換到SWAP,而做改變.而VmRSS則由461208KB變成了386704KB,說明它佔用的實體記憶體因為置換所以減少. VmData: 33980 kBVmStk: 88 kBVmExe: 320 kBVmLib: 2044 kB 解釋:VmData:表示進程資料區段的大小.VmStk:表示進程堆棧段的大小.VmExe:表示進程代碼的大小.VmLib:表示進程所使用LIB庫的大小. 關於程式碼片段,堆棧段,資料區段:程式碼片段可以為機器中運行同一程式的數個進程共用堆棧段存放的是子程式(函數)的返回地址、子程式的參數及程式的局部變數資料區段則存放程式的全域變數、常數以及動態資料分配的資料空間(比如用malloc函數申請的記憶體)與程式碼片段不同,如果系統中同時運行多個相同的程式,它們不能使用同一堆棧段和資料區段. 注意:堆棧段代表的是程式中的堆區(stack),堆區一般是編譯器自動分配釋放的.我們用malloc申請的記憶體,它佔用的其實是棧區(heap),棧區一般是程式員自已指派釋放的,而棧區在這裡屬於資料區段,所以我們看到上面測試程式通過調用malloc函數後,VmData一值有了很大的變化. VmPTE: 56 kBVmSwap: 0 kB VmPTE: 56 kB解釋:佔用的頁表的大小. VmSwap: 0 kB解釋:進程佔用Swap的大小. Threads: 3解釋:表示當前進程組有3個線程. SigQ: 1/7954解釋:表示當前待處理訊號的個數,我們用下面和程式進行測試,如下:#include#include#include#include#include volatile int done = 0; void handler (int sig){ const char *str = "handled...\n"; write (1, str, strlen(str)); done = 1;} void child(void){ int i; for (i = 0; i < 3; i++){ kill(getppid(), SIGRTMIN); printf("child - BANG!\n"); } exit (0);} int main (int argc, char *argv[]){ signal (SIGRTMIN, handler); sigset_t newset, oldset; sigfillset(&newset); sigprocmask(SIG_BLOCK, &newset, &oldset); pid_t pid = fork(); if (pid == 0) child(); printf("parent sleeping \n"); int r = sleep(30); printf("woke up! r=%d\n", r); sigprocmask(SIG_SETMASK, &oldset, NULL); while (!done){ }; printf("exiting\n"); exit(0);} 編譯:gcc sig.c -o sig本程式會發達三次訊號,此後進入sleep,我們可以在這期間來查看待處理訊號的個數,如下:./sigparent sleeping child - BANG!child - BANG!child - BANG!woke up! r=0handled...handled...handled...exiting cat /proc/`pgrep sig`/status略SigQ: 4/4294967295略 我們發送了三次訊號,這裡為什麼是4呢,因為我們用了fork派生了子進程,子進程結束後會發送SIGCHLD訊號.所以這裡有4個訊號待處理. SigPnd: 0000000000000000ShdPnd: 0000000000000000SigBlk: 0000000000000000SigIgn: 0000000001001206SigCgt: 0000000180014c21解釋:SigPnd:屏蔽位,儲存了該線程的待處理訊號,等同於線程的PENDING訊號.ShnPnd:屏蔽位,儲存了該線程組的待處理訊號.等同於進程組的PENDING訊號.SigBlk:存放被阻塞的訊號,等同於BLOCKED訊號.SigIgn:存放被忽略的訊號,等同於IGNORED訊號.SigCgt:存放捕獲的訊號,等同於CAUGHT訊號. CapInh: 0000000000000000CapPrm: ffffffffffffffffCapEff: ffffffffffffffffCapBnd: ffffffffffffffff解釋:CapEff:當一個進程要進行某個特權操作時,作業系統會檢查cap_effective的對應位是否有效,而不再是檢查進程的有效UID是否為0.CapPrm:表示進程能夠使用的能力,在cap_permitted中可以包含cap_effective中沒有的能力,這些能力是被進程自己臨時放棄的,也可以說cap_effective是cap_permitted的一個子集.CapInh:表示能夠被當前進程執行的程式繼承的能力.CapBnd:是系統的邊界能力,我們無法改變它. Cpus_allowed: 3Cpus_allowed_list: 0-1解釋:Cpus_allowed:3指出該進程可以使用CPU的親和性掩碼,因為我們指定為兩塊CPU,所以這裡就是3,如果該進程指定為4個CPU(如果有話),這裡就是F(1111).Cpus_allowed_list:0-1指出該進程可以使用CPU的列表,這裡是0-1.Mems_allowed: 1Mems_allowed_list: 0記憶體同CPU一樣,進程rsyslogd只是使用了結點0的記憶體資源. 我們這裡調整該進程到CPU0,如下:taskset -p 1 987pid 987‘s current affinity mask: 3pid 987‘s new affinity mask: 1 cat /proc/987/status略Cpus_allowed: 1Cpus_allowed_list: 0Mems_allowed: 1Mems_allowed_list: 0注:我們看到Cpus_allowed/Cpus_allowed_list較之前有了變化.Cpus_allowed由3變成了1.表明我們只會用CPU0. voluntary_ctxt_switches: 1nonvoluntary_ctxt_switches: 0 voluntary_ctxt_switches表示進程主動切換的次數.nonvoluntary_ctxt_switches表示進程被動切換的次數. 首先查看一下當前進程,如下:echo $$1544 執行如下命令:while ((1)); do echo 1; sleep 1; done 查看該進程的主動切換與被動切換,如下:cat status略voluntary_ctxt_switches: 949nonvoluntary_ctxt_switches: 55我們看到主動切換和被動切換有了明顯的變化. 轉自:http://blog.csdn.net/zyboy2000/article/details/50425626
Linux下進程資訊的深入分析