1. 程式人生 > >Linux下程序資訊的深入分析

Linux下程序資訊的深入分析

這裡我們主要介紹程序的狀態,程序的狀態可以通過/proc/PID/status來檢視,也可以通過/proc/PID/stat來檢視. 如果說到工具大家用的最多的ps也可以看到程序的資訊.這裡我們通過/proc/PID/status來分析程序的資訊. 在2.6.18之後的核心,多了capibilty/cpusets等資訊. 檢視程序狀態資訊如下: more status  Name:   rsyslogd State:  S (sleeping) Tgid:   987 Pid:    987 PPid:   1 TracerPid:      0 Uid:    0       0       0       0 Gid:    0       0       0       0 Utrace: 0 FDSize: 32 Groups: VmPeak:    36528 kB VmSize:    36528 kB VmLck:         0 kB VmHWM:      1432 kB VmRSS:      1420 kB VmData:    33980 kB VmStk:        88 kB VmExe:       320 kB VmLib:      2044 kB VmPTE:        56 kB VmSwap:        0 kB Threads:        3 SigQ:   1/7954 SigPnd: 0000000000000000 ShdPnd: 0000000000000000 SigBlk: 0000000000000000 SigIgn: 0000000001001206 SigCgt: 0000000180014c21 CapInh: 0000000000000000 CapPrm: ffffffffffffffff CapEff: ffffffffffffffff CapBnd: ffffffffffffffff Cpus_allowed:   3 Cpus_allowed_list:      0-1 Mems_allowed:   1 Mems_allowed_list:      0 voluntary_ctxt_switches:        1 nonvoluntary_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 CMD root       987     1   987  0    3 00:18 ?        00:00:00 /sbin/rsyslogd -c 4 root       987     1   989  0    3 00:18 ?        00:00:00 /sbin/rsyslogd -c 4 root       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 -axjf PPID   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/stat stat    statm   status   test1:/proc/2431# cat /proc/2501/status  Name:   top State:  S (sleeping) Tgid:   2501 Pid:    2501 PPid:   2500 TracerPid:      2500 Uid:    0       0       0       0 Gid:    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 - test top 檢視該程序的EUID和RUID,如下: 終端2) cat /proc/`pgrep top|grep -v grep`/status 前面略 Uid:    1002    1002    1002    1002 Gid:    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       0 Gid:    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 0 lrwx------ 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.log l-wx------ 1 root root 64 2011-04-20 20:03 10 -> /var/log/mail.err l-wx------ 1 root root 64 2011-04-20 20:03 11 -> /var/log/news/news.crit l-wx------ 1 root root 64 2011-04-20 20:03 12 -> /var/log/news/news.err l-wx------ 1 root root 64 2011-04-20 20:03 13 -> /var/log/news/news.notice l-wx------ 1 root root 64 2011-04-20 20:03 14 -> /var/log/debug l-wx------ 1 root root 64 2011-04-20 20:03 15 -> /var/log/messages lrwx------ 1 root root 64 2011-04-20 20:03 16 -> /dev/xconsole lr-x------ 1 root root 64 2011-04-20 20:03 17 -> /proc/kmsg l-wx------ 1 root root 64 2011-04-20 20:03 2 -> /var/log/syslog l-wx------ 1 root root 64 2011-04-20 20:03 3 -> /var/log/daemon.log l-wx------ 1 root root 64 2011-04-20 20:03 4 -> /var/log/kern.log l-wx------ 1 root root 64 2011-04-20 20:03 5 -> /var/log/lpr.log l-wx------ 1 root root 64 2011-04-20 20:03 6 -> /var/log/mail.log l-wx------ 1 root root 64 2011-04-20 20:03 7 -> /var/log/user.log l-wx------ 1 root root 64 2011-04-20 20:03 8 -> /var/log/mail.info l-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)裡面,如下: id uid=1002(test) gid=1002(nagcmd) groups=1000(chenkuo),1002(nagcmd) 用test使用者啟動top程式,並檢視它的groups,如下: 終端1 top 終端2 cat /proc/`pgrep top|grep -v grep`/status 擷取資訊如下: Groups: 1000 1002  VmPeak:    36528 kB 解釋:這裡的VmPeak代表當前程序執行過程中佔用記憶體的峰值. 我們用下面的程式申請記憶體,然後釋放記憶體,最後通pause()函式中止程式的執行,程式原始碼如下: #include #include #include #include int main (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 10 allocated 10 mb 終端2 我們開啟status檔案,檢視VmPeak值,如下: cat /proc/`pgrep callmem|grep -v grep`/status Name:   callmem State:  S (sleeping) Tgid:   2930 Pid:    2930 PPid:   2831 TracerPid:      0 Uid:    1002    1002    1002    1002 Gid:    1002    1002    1002    1002 FDSize: 256 Groups: 1000 1002  VmPeak:    11852 kB VmSize:     1608 kB VmLck:         0 kB VmHWM:       396 kB VmRSS:       396 kB VmData:       28 kB VmStk:        84 kB VmExe:         4 kB VmLib:      1468 kB VmPTE:        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`/status Name:   memlock State:  S (sleeping) Tgid:   3249 Pid:    3249 PPid:   3139 TracerPid:      0 Uid:    0       0       0       0 Gid:    0       0       0       0 FDSize: 256 Groups: 0  VmPeak:     1624 kB VmSize:     1608 kB VmLck:         4 kB VmHWM:       356 kB VmRSS:       356 kB VmData:       28 kB VmStk:        84 kB VmExe:         4 kB VmLib:      1468 kB VmPTE:        16 kB 我們看到Vmlck的值為4Kb,這是因為分配的最少單位是4KB,以後每次遞增都是4KB的整數倍. VmHWM:      1432 kB VmRSS:      1420 kB 解釋: VmHWM是程式得到分配到實體記憶體的峰值. VmRSS是程式現在使用的實體記憶體. 我們用下面的程式進行測試,如下: #include #include #include #include int main (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     cached Mem:           503         18        484          0          0          5 -/+ buffers/cache:         12        490 Swap:         7632          7       7624 我們看到當前有490MB的空閒實體記憶體. 執行callmem分配450MB的實體記憶體,如下: ./test 450& [1] 2402 allocated 450 mb 我們檢視程序的VmHWM和VmRSS,如下: cat /proc/`pgrep test`/status 略 VmHWM:    461208 kB VmRSS:    461208 kB 略 我們看到此時VmHWM和VmRSS是一樣的,表示佔用了460MB左右的實體記憶體(因為它會用到動態連結庫等). 下面我們檢視當前的記憶體使用情況,如下: free -m              total       used       free     shared    buffers     cached Mem:           503        470         33          0          0          6 -/+ buffers/cache:        463         40 Swap:         7632          7       7625 我們看到還有40MB空閒實體記憶體. 我們下面再申請100MB的記憶體,此時系統會通過實體記憶體和SWAP的置換操作,把第1次執行的test程序所佔用的實體記憶體置換到SWAP,把空出來的實體記憶體分配給第2次執行的程式,如下: mv test test1 ./test1 100& [1] 2419 allocated 100 mb 再次檢視test程序所佔用的實體記憶體,如下: cat /proc/`pgrep test`/status 略 VmHWM:    461208 kB VmRSS:    386704 kB 略 最後我們看到VmHWM沒有變化,因為它表示的是該程序所佔用實體記憶體的峰值,不會因為把記憶體置換到SWAP,而做改變. 而VmRSS則由461208KB變成了386704KB,說明它佔用的實體記憶體因為置換所以減少. VmData:    33980 kB VmStk:        88 kB VmExe:       320 kB VmLib:      2044 kB 解釋: VmData:表示程序資料段的大小. VmStk:表示程序堆疊段的大小. VmExe:表示程序程式碼的大小. VmLib:表示程序所使用LIB庫的大小. 關於程式碼段,堆疊段,資料段: 程式碼段可以為機器中運行同一程式的數個程序共享 堆疊段存放的是子程式(函式)的返回地址、子程式的引數及程式的區域性變數 資料段則存放程式的全域性變數、常數以及動態資料分配的資料空間(比如用malloc函式申請的記憶體) 與程式碼段不同,如果系統中同時執行多個相同的程式,它們不能使用同一堆疊段和資料段. 注意: 堆疊段代表的是程式中的堆區(stack),堆區一般是編譯器自動分配釋放的. 我們用malloc申請的記憶體,它佔用的其實是棧區(heap),棧區一般是程式設計師自已分配釋放的,而棧區在這裡屬於資料段,所以我們看到上面測試程式通過呼叫malloc函式後,VmData一值有了很大的變化. VmPTE:        56 kB VmSwap:        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();

相關推薦

Linux程序資訊深入分析

這裡我們主要介紹程序的狀態,程序的狀態可以通過/proc/PID/status來檢視,也可以通過/proc/PID/stat來檢視. 如果說到工具大家用的最多的ps也可以看到程序的資訊.這裡我們通過/proc/PID/status來分析程序的資訊. 在2.6.18之後

Linux 程序許可權分析

在linux下,關於檔案許可權,大部分人接觸比較多,也比較熟悉瞭解.但是對程序許可權一般知之甚少。本文總結一下linux系統下程序許可權問題和現象。 需要強調的是,本文是linux系統下討論,因為linux和unix有很多不同的地方,並且各個不同的unix系統也有很

Linux堆記憶體管理深入分析

Linux堆記憶體管理深入分析 (下半部) 作者@走位,阿里聚安全 0 前言回顧 在上一篇文章中,詳細介紹了堆記憶體管理中涉及到的基本概念以及相互關係,同時也著重介紹了堆中chunk分配和釋放策略中使用到的隱式連結串列技術。通過前面的介紹,我們知道使用隱式連結串

Linux程序的建立過程分析(_do_fork/do_fork詳解)--Linux程序的管理與排程(八)

前言 Unix標準的複製程序的系統呼叫時fork(即分叉),但是Linux,BSD等作業系統並不止實現這一個,確切的說linux實現了三個,fork,vfork,clone(確切說vfork創造出來的是輕量級程序,也叫執行緒,是共享資源的程序

linux程序JDBC連接不到mysql數據庫

var 進入 日誌 啟動報錯 span -- start -s 啟動mysql   今天在linux下部署一個 JavaEE項目的時候總是連接不到Mysql數據庫,檢查之後發現連接池的配置確定是對的,進入linux服務器之後以mysql -uname -ppassword連

Linux程序的總結(3)

程序的控制 1.程序的建立 fork()函式 在一個程式碼段中建立一個新的子程序可以使用fork()函式。 1.fork()函式以父程序為模板創建出了一個子程序,但是父子程序程式碼共享,資料獨有一份。也就是分配新的記憶體塊和核心資料結構。然後父程序的部分資料拷貝到了子程序。

Linux程序的總結(2)

程的優先順序 由於每個程序的任務所要消耗的資源量不同。所以要對程序進行分級制度。 為什麼要有程序的優先順序? 計算機只有一個cpu,採用了分時機制,讓每個程式在cpu上執行很短的時間。這個時間非常短,人的感知無法仔細的觀察到。切換時間片的時候,有的程序需要緊急處理,有的程序可以放

Linux程序知識(1)

#Linux 下程序的總結(1) ##什麼是程序? 程序是程式執行一次的過程。它佔用了CPU,佔用了記憶體的資源。 作業系統為了將各個程序統一管理起來。將每一個程序定義成了一個小塊,這個小塊被稱之為PCB(Program control blocks) 程式控制塊。通常情況下我們可以

Linux程序間通訊方式 - UNIX Domain Socket

概述 Linux下程序通訊方式有很多,比較典型的有套接字,平時比較常用的套接字是基於TCP/IP協議的,適用於兩臺不同主機上兩個程序間通訊, 通訊之前需要指定IP地址. 但是如果同一臺主機上兩個程序間通訊用套接字,還需要指定ip地址,有點過於繁瑣. 這個時候就需要用到UNIX Domain Sock

Linux IO 監控與深入分析

4.6 .cn 計時 說明 扇區 版本 play linux patch https://jaminzhang.github.io/os/Linux-IO-Monitoring-and-Deep-Analysis/ Linux IO 監控與深入分析 引言 接昨天電話面試

linux程序、以及程序間的通訊機制

2.1程序基本概念         程序是Linux事務管理的基本單元,所有的程序均擁有自己獨立的處理環境和系統資源。程序的環境由當前系統狀態及其父程序資訊決定和組成。系統的第一個程序init由核心產生,以後所有的程序都是

Linux程序程式替換及簡單的shell的實現

替換原理: 用fork建立程序後執行的是和父程序相同的程式(但有可能執行不同的程式碼分支),子程序往往要呼叫exec函式以執行另一個程式。當程序呼叫一種exec函式時,該程序的使用者空間程式碼和資料完全被新程式替換。從新程序的啟動例程開始執行,呼叫exec函式並不建立新程序

Linux使用者資訊

-使用者資訊- ** 除了著名的init程式以外,所有的Linux程式都是由其他程式或使用者啟動的。使用者通常是在一個響應他們命令的shell(命令解析器)中啟動程式。程式能夠通過檢查環境變數和讀取系統時鐘來在很大程度上了解它所處的執行環境。程式也能夠發現它的使

linux 程序學習(1)

fork() ----- #include <unistd.h> #include <stdio.h> int main() {      pid_t t;      printf("father pid %d\n",(int)getpid()

Linux的段錯誤分析

2. 段錯誤產生的原因 2.1 訪問不存在的記憶體地址 #include #includevoid main() {int *ptr = NULL;*ptr = 0; } 2.2 訪問系統保護的記憶體地址 #include #includevoid main() {

linux程序和執行緒狀態檢視

檢查 使用 ps -fe |grep programname 檢視獲得程序的pid,再使用 ps -Lf pid 檢視對應程序下的執行緒數. 查詢資料發現可以通過設定 ulimit -s 來增加每程序執行緒數。 每程序可用執行緒數 = VIRT上限/stack size

linux程序的狀態

Linux是一個多使用者,多工的系統,可以同時執行多個使用者的多個程式,就必然會產生很多的程序,而每個程序會有不同的狀態。 Linux程序狀態:R (TASK_RUNNING),可執行狀態。      只有在該狀態的程序才可能在CPU上執行。

linux程序號檢視與結束程序

最近開始看資料結構和演算法,看的是C 的版本,所以今天在虛擬機器上裝了CentOS的系統,打算用linux自帶的gcc和gdb來學習。 以前用的linux作業系統都是ubuntu,突然換了centos

linuxvlan的實現分析(上)

一. VLAN的核心概念     1. 劃分VLAN的核心目的只有一個:分割廣播域。        通過VLAN對廣播域進行合理分割之後,一是可以縮小ARP攻擊的範圍,從而提高網路的安全性;二是可以縮小廣播域的大小,從而提高網路的效能。        所以要注意的是,劃分V

linux程序間通訊的幾種主要方式簡介

      共享記憶體是執行在同一臺機器上的程序間通訊最快的方式,因為資料不需要在不同的程序間複製。通常由一個程序建立一塊共享記憶體區,其餘程序對這塊記憶體區進行讀寫。共享記憶體往往與其它通訊機制,如訊號量結合使用,來達到程序間的同步及互斥。  首先要用的函式是shmget,它獲得一個共享儲存識別符號。