1. 程式人生 > 實用技巧 >-linux-程序管理

-linux-程序管理

一 程序介紹

程式:存放程式碼的檔案 (靜態)

程序:程式的執行過程 (動態)

同一個程式可能對應多個程序

父程序:程式執行時產生的第一個程序

子程序:由父程序衍生fork()出來的程序

注意:如果父程序終止,子程序也會隨之被終止 (守護程序)

[root@arther-linux ~]# yum install nginx -y
[root@arther-linux ~]# systemctl start nginx
[root@arther-linux ~]# ps aux |grep nginx
root      2037  0.0  0.0 112824   980 pts/0    S+   18:37   0:00 grep --color=auto ngin

1 程序-程序狀態(R、S、D、T、Z、X)

程序概念

  • 正在執行的程式
  • 正在計算機執行的程式例項
  • 能分配處理器並有處理器執行的實體

程序的兩個基本元素是程式程式碼和程式碼想關聯的資料集。程序是一種動態描述,但並不代表所有的程序都在執行。這就可以引入程序狀態。

程序在記憶體中因策會略或排程需求,

會處於各種狀態:

Linux下的程序狀態

static const char * const task_state_array[] = { 
"R (running)", /* 0 */ 
"S (sleeping)", /* 1 */ 
"D (disk sleep)", /* 2 */ 
"T (stopped)", /* 4 */ 
"t (tracing stop)", /* 8 */ 
"X (dead)", /* 16 */ 
"Z (zombie)", /* 32 */ 
};

# R- 可執行狀態(執行狀態)
只有在執行狀態的程序才有可能在CPU上執行,注意是可能,並不意味著程序一定在執行中。同一時刻可能有 多個程序處在可執行狀態,這些程序的PCB(程序控制塊)被放入對應CPU的可執行佇列中。然後程序排程器 從各個可執行佇列中分別選擇一個程序在CPU上執行。 另外如果計算機只有一個處理器,那麼一次最多隻有一個程序處於這種狀態。
(在此狀態下等待被cpu呼叫)

# S- -可中斷睡眠狀態(sleeping) 
處在這個狀態意味著程序在等待事件完成。這些程序的PCB(task_struct結構)被放入對應時間的等待佇列 中。然後等待的事件發生時,對應的程序將被喚醒。

# D- -不可中斷睡眠(disk sleep) 
在這個狀態的程序通常會等待IO的結束。 這個狀態與sleeping狀態相似,處於睡眠狀態,但是此刻程序是不可中斷的,意思是不響應非同步訊號。 另外你會發現處在D狀態的程序kill -9竟然也殺不死。這就相當於我們怎麼也叫不醒一個裝睡的人。

# T- -暫停狀態 
給程序傳送一個SIGSTOP訊號,程序就會響應訊號進入T狀態,除非該程序正處在D狀態。 再通過傳送SIGCONT訊號讓程序繼續執行。 
kill -SIGSTOP 
kill -SIGCONT

# Z- -僵死狀態 
僵死狀態是一個比較特殊的狀態。程序在退出的過程中,處於TASK_DEAD狀態。 在這個退出過程中,程序佔有的所有資源將被回收,除了task_struct結構(以及少數資源)以外。於是進 程就只剩下task_struct這麼個空殼,故稱為殭屍。 
X- -死亡狀態或退出狀態(dead) 
死亡狀態是核心運⾏ kernel/exit.c ⾥的 do_exit() 函式返回的狀態。這個狀態只是⼀個返回狀態, 你不會在任務列表⾥看到這個狀態
(pid沒有被回收,還佔用著cpu資源)

程序狀態切換

程序在執行中不斷的改變執行狀態;

  • 就緒狀態

    當程序已分配到除CPU以外的所有必要的資源,只要獲得處理機便可立即執行,這時的程序狀態稱為就緒狀態。

  • 執行(Running)狀態

    當程序已獲得處理機,其程式正在處理機上執行,此時的程序狀態稱為執行狀態 。

  • 阻塞(Blocked)狀態

    正在執行的程序,由於等待某個事件發生而無法執行時,便放棄處理機而處於阻塞狀態。引起程序阻塞的事件可有多種,例如,等待I/O完成、申請緩衝區不能滿足、等待信件(訊號)等。

就緒–>執行
處在就緒狀態的程序,當排程器為其分配了處理機後,就變成了執行狀態。

執行–>就緒
執行狀態的程序在其執行過程中,時間片跑完了不得不讓出處理機,於是從執行變成就緒狀態。

執行–>阻塞
正在執行的程序等待某種事件而無法繼續執行時,便從執行狀態變成阻塞狀態。

阻塞–>就緒
處在阻塞狀態的程序,如果等待的時間發生,則從阻塞狀態轉變成就緒狀態。

二 檢視程序

ps aux是常用組合,檢視程序使用者、PID、佔用CPU百分比、佔用記憶體百分比、狀態、執行的命令等。

-a 				# 顯示一個終端的所有程序

-u				# 選擇有效的使用者id或者是使用者名稱

-x				# 顯示沒有控制終端的程序,同時顯示各個命令的具體路徑

示例

[root@arther-linux ~]# ps aux |head -5
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.3 128816  7392 ?        Ss   05:17   0:17 /usr/lib/systemd/systemd --system --deserialize 15
root         2  0.0  0.0      0     0 ?        S    05:17   0:00 [kthreadd]
root         4  0.0  0.0      0     0 ?        S<   05:17   0:00 [kworker/0:0H]
root         6  0.0  0.0      0     0 ?        S    05:17   0:00 [ksoftirqd/0]

檢視結果顯示

USER:				執行程序的使用者
  
PID:				程序ID
  
%CPU:				CPU佔用率
  
%MEN:				記憶體佔用率
  
VSZ:				佔用虛擬記憶體,單位:kb
    				VSZ是指已分配的線性空間大小,這個大小通常並不等於程式實際用到的記憶體大						小,產生這個的可 能性很多 比如記憶體對映,共享的動態庫,或者向系統申請了						更多的堆,都會擴充套件線性空間大小。
      
RSS:				佔用實際記憶體,單位:kb
    				RSZ是Resident Set Size,常駐記憶體大小,即程序實際佔用的實體記憶體大小
      
TTY:				程序執行的終端
  
STAT:				程序狀態
  					R 執行 
    				S 可中斷睡眠 
      			Sleep,即在睡眠的過程中可以接收訊號喚醒=》執行的IO操作可以得到硬體設 						 備的響應
        		D 不可中斷睡眠,即在睡眠的過程中不可以接收訊號喚醒=》執行的IO操作得不						 到硬體裝置的響應 
          	T 停止的程序 
            Z 殭屍程序 
            X 死掉的程序(幾乎看不見,因為死了就立即回收了) 
            < 標註了<小於號代表優先順序較高的程序 
            N N代表優先順序較低的程序 
            s 包含子程序 
            + +表示是前臺的程序組 l 小寫字母l,代表以執行緒的方式執行,即多執行緒 
            | 管道符號代表多程序

START: 			程序的啟動時間 
  
TIME: 		 	程序佔用CPU的總時間
  
COMMAND:	  程序檔案,程序名 
  					帶[]號的代表核心態程序 
    				不帶[]號的代表使用者態程序

Linux 程序有兩種睡眠狀態

# 1、Interruptible Sleep(可中斷睡眠,在ps命令中顯示“S”) 
處在這種睡眠狀態的程序是可以通過給它傳送signal來喚醒的,比如發HUP訊號給nginx的master程序可以 讓nginx重新載入配置檔案而不需要重新啟動nginx程序; 

# 2、Uninterruptible Sleep(不可中斷睡眠,在ps命令中顯示“D”) 
處在這種狀態的程序不接受外來的任何signal,這也是為什麼之前我無法用kill殺掉這些處於D狀態的進 程,無論是“kill”、“kill -9”、“kill -15”還是按 Ctrl+C 、Ctrl+Z 都無濟於,因為它們壓根兒就 不受這些訊號的支配。 

# 解釋 
程序為什麼會被置於D狀態呢?處於uninterruptible sleep狀態的程序通常是在等待IO,比如磁碟IO, 網路IO,其他外設IO,如果程序正在等待的IO在較長的時間內都沒有響應,那麼就很會不幸地被ps看到了, 同時也就意味著很有可能有IO出了問題,可能是外設本身出了故障,也可能是比如NFS掛載的遠端檔案系統已 經不可訪問了。 正是因為得不到IO的響應,程序才進入了uninterruptible sleep狀態,所以要想使程序從 uninterruptible sleep狀態恢復,就得使程序等待的IO恢復,比如如果是因為從遠端掛載的NFS卷不可 訪問導致程序進入uninterruptible sleep狀態的,那麼可以通過恢復該NFS卷的連線來使程序的IO請求 得到滿足,除此之外,要想幹掉處在D狀態程序就只能重啟整個Linux系統了(恐怖的D狀態)。

看到有人說如果要想殺掉D狀態的程序,通常可以去殺掉它的父程序(通常是shell,我理解的這種情況是在 shell下直接執行的該程序,之後該進 程轉入了D狀態),於是我就照做了,之後就出現了上面的狀態:他們 的父程序被殺掉了,但是他們的父程序PID都變成了1,也就是init程序,這下可如何是好?此時我這些D狀態 的程序已經影響到其他一些程序的執行,而已經無法訪問的NFS卷又在段時間內無法恢復,那麼,只好重新啟 動了。

# 強調 
D與Z狀態的程序都無法用kill -9殺死

示例

-1.在視窗1執行vim命令
[root@arther-linux /]# vim 1.txt 

-2.在視窗2檢視vim的執行狀態為:S+
[root@arther-linux ~]# ps aux |grep [v]im
root      8065  0.1  0.2 149620  5188 pts/0    S+   17:50   0:00 vim 1.txt
    
-3.在視窗1執行:ctrl+z,將程序放置到後臺
[root@egon ~]# vim egon.txt 
[4]+ 已停止 vim egon.txt

-4.在視窗2檢視vim的執行狀態為:T
[root@egon ~]# ps aux |grep [v]im root 
103231 0.3 0.2 149828 5460 pts/2 T 17:48 0:00 vim egon.txt

檢視程序樹

[root@arther-linux /]# pstree

檢視ppid

[root@arther-linux /]# ps -ef | head -10
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 05:17 ?        00:00:17 /usr/lib/systemd/systemd --system --deserialize 15
root         2     0  0 05:17 ?        00:00:00 [kthreadd]
root         4     2  0 05:17 ?        00:00:00 [kworker/0:0H]
root         6     2  0 05:17 ?        00:00:00 [ksoftirqd/0]
root         7     2  0 05:17 ?        00:00:01 [migration/0]
root         8     2  0 05:17 ?        00:00:00 [rcu_bh]
root         9     2  0 05:17 ?        00:00:20 [rcu_sched]
root        10     2  0 05:17 ?        00:00:00 [lru-add-drain]
root        11     2  0 05:17 ?        00:00:00 [watchdog/0]

動態檢視

-1.基本用法
[root@arther-linux /]# top
[root@arther-linux /]# top -d 1 # 1秒檢視一次

三 管理程序

1 關於HUP訊號

要了解Linux的HUP訊號,需要從hangup說起

在 Unix 的早期版本中,每個終端都會通過 modem 和系統通訊。 
當用戶 logout 時,modem 就會結束通話(hang up)電話。 
同理,當 modem 斷開連線時,就會給終端傳送 hangup 訊號來通知其關閉所有子程序。

綜上,我們知道,當用戶登出(logout)或者網路斷開或者終端關閉(注意注意注意,一定是終端整體關閉,不是單純的exit)時,終端都會收到Linux HUP訊號(hangup)訊號,然後終端在結束前會關閉其所有子程序。如果我們想讓我們的程序在後臺一直執行,不要因為使用者登出(logout)或者網路斷開或者終端關閉而一起被幹掉,那麼我們有兩種解決方案。

  • 方案1:讓程序忽略Linux HUP訊號

  • 方案2:讓程序執行在新的會話裡,從而成為不屬於此終端的子程序,就不會在當前終端掛掉的情況下一起被帶走。

2 nohup命令

針對方案1,我們可以使用nohup命令,nohup 的用途就是讓提交的命令忽略 hangup 訊號,該命令通常與&符號一起使用。

nohup 的使用是十分方便的,只需在要處理的命令前加上 nohup 即可,但是 nohup 命令會從終端解除進 程的關聯,程序會丟掉STDOUT,STDERR的連結。標準輸出和標準錯誤預設會被重定向到 nohup.out 檔案 中。一般我們可在結尾加上"&"來將命令同時放入後臺執行,也可用">filename 2>&1"來更改預設的重定向 檔名。

3 screen命令

# 1、安裝 [root@egon ~]# yum install screen -y 

# 2、執行命令 
方式一:開啟一個視窗並用-S指定視窗名,也可以不指定 
[root@egon ~]# screen -S egon_dsb 
''' Screen將建立一個執行shell的全屏視窗。你可以執行任意shell程式,就像在ssh視窗中那樣。 在該視窗中鍵入exit則退出該視窗,如果此時,這是該screen會話的唯一視窗,該screen會話退出,否則 screen自動切換到前一個視窗。 
''' 

方式二:Screen命令後跟你要執行的程式 
[root@egon ~]# screen vim test.txt

''' 
Screen建立一個執行vim test.txt的單視窗會話,退出vim將退出該視窗/會話。
'''
# 3、原理分析 
screen程式會幫我們管理執行的命令,退出screen,我們的命令還會繼續執行,若關閉screen所在的終 端,則screen程式的ppid變為1,所以screen不會死掉,對應著它幫我們管理的命令也不會退出 測試略 

# 4:重新連線會話 
在終端1中執行 
[root@egon ~]# screen 
[root@egon ~]# n=1;while true;do echo $n;sleep 1;((n++));done 
[root@egon ~]# 按下ctrl+a,然後再按下ctrl+d,注意要連貫,手別哆嗦, 
[root@egon ~]# 此時可以關閉整個終端,我們的程式並不會結束 

開啟一個新的終端 
[root@egon ~]# screen -ls 
There is a screen on: 
  109125.pts-0.egon (Detached) 
1 Socket in /var/run/screen/S-root. 

[root@egon ~]# screen -r 109125 # 會繼續執行 
[root@egon ~]# 

注意:如果我們剛開始已經用screen -S xxx指定了名字,那麼我們其實可以直接 screen -r xxx ,就無須去找程序id了