1. 程式人生 > 實用技巧 >Linux程序的相關概念、核心的狀態

Linux程序的相關概念、核心的狀態

第1章 程序的相關概念

1.1 程序的建立

除了init(該程序是由核心建立而來)
其餘的任何程序都是有父程序fork自身而來的,fork之後一般會克隆自己的資料給子程序

當一個程序建立一個子程序的時候,此時子程序一定是和父程序使用的是同一段記憶體空間,只不過這個子程序有自己的名字(即程序ID號)
一旦子程序需要去修改資料的時候,父程序是不允許的,此時父程序就會把資料克隆一份給子程序,相當於個子程序自己一個家,此時子程序在自己的家裡
想怎麼修改就怎麼修改,這種機制就是寫時複製(Cow)

1.2 父程序為什麼要建立子程序

當父程序在執行過程中,需要完成一個複雜的功能時,乾脆啟動另一個程序,讓這個程序去完成這個複雜的功能,
只需要把結果返回給父程序即可。當子程序完成這個任務時,它的生命週期就完成了,這也就是為什麼在程序的世界裡都是白髮人送黑髮人的原因

1.3 核心時怎麼排程程序的

假設此時有一百個程序在等待需要排程,核心怎麼去判斷需要先執行哪個,再執行哪個呢?
首先想到的是,把這100個程序全部遍歷一遍做比較,如果這樣去排程的話(如果有一萬個程序呢?),效能會非常差
為了解決這種問題,Linux從核心2.6開始,把程序的優先順序劃分了固定的個數
0~139
  0~99: 實時優先順序(但是0一般不會用到,所以1~99)
      數字越大,優先順序越高,(一般很少需要手動處理)
  100~139:使用者可排程的優先順序
          數字越小,優先順序越高
Nice值(分別對應100~139這40個數字):-20~19
因此,Linux在眾多等待的程序中,會按照優先順序把它們分成140個佇列,當需要排程時,只需要掃描這些佇列的首部就可以了(從高到低),所以不管佇列有多長,對核心排程來說都是一樣的

1.3.1 執行佇列和過期佇列

核心在進行排程時,不是說把整個程序執行完了在執行第2個程序,而是給當前排程的程序分配一段時間,當這段時間執行完了就會把這個程序踢下去,執行下一個程序
例如:
有一個程序執行完成需要10秒,而核心只給了它5秒中,5秒到了以後,它只能等待下一次排程!那此時應該把這個沒有執行完的程序放到哪去呢?
一般來說,程序優先順序的佇列都分為2隊,一隊叫執行佇列,一隊叫過期佇列。所以這樣一來不是140對而是280對。當執行佇列完成後,不需要切換
而是執行佇列和過期佇列2者互換身份,這樣不停的在執行佇列和過期佇列中切換中排程程序

1.4 程序在自己的儲存內部空間到底應該存的是什麼

1.4.1 程序記憶體(不是十分精確,為了便於理解)

系統啟動以後,核心會先佔據實體記憶體的一部分,剩下的空間會被分割為若干大小的Page Frame(頁框[預設大小為4K],用於儲存頁面資料),
用於儲存page,每一個程序起來以後,核心給其分配記憶體,從眾多頁框中,找一些空閒的頁框給它,實際上程序的記憶體是這樣拼湊起來的
所以,整個實體記憶體空間是以這種大量的不連續的或者部分連續的頁框組成的,將這些頁框分配給程序,讓程序以為自己的記憶體看起來時連續的一樣
怎麼樣能使這些不連續的看起來像連續的呢?
中間加一層虛擬層,所以每一個程序看到的都是虛擬記憶體,而不是真正的實體記憶體

1.4.2 線性地址空間和實體地址空間

由於程序看到的都是虛擬記憶體,所以每一個程序都會認為,整個實體記憶體,除了核心記憶體,其次就是自己了,而實際上只有幾個頁框而已
例如:
實體記憶體,被核心佔用後還有3G,程序會認為這3G全是自己的,實際上程序自己佔用的記憶體空間很小,這種機制就是線性記憶體管理機制
而程序以為自己佔用的3G記憶體空間就叫做線性地址空間
而真正分配物理的實體記憶體就叫做實體地址空間

1.4.3 實體記憶體不夠使用時

當實體記憶體真的不夠用時,就會使用到交換分割槽
  怎麼交換呢?
會把實體記憶體的頁框(根據最近最少使用的演算法[LRU])暫時挪到磁碟上去,這樣就有一段空間在實體記憶體上騰出來了,萬一挪出來的這段空間又要被使用,
只能把其它的空間調出來,把這段空間調進去,但是調回去後不是原來的地址了,因為這段實體地址空間和線性地址空間是有對映關係的
對映關係是在task strck儲存這
訪問資料的時候,只能根據程序的線性地址空間,根據對映關係找到實體記憶體地址空間,這樣才能對其進行操作!這個過程在CPU中有一個專門的晶片來完成,
叫做MMU.所以,當我們把頁框再次挪進去的時候,就需要把對映關係重新對映

1.5 缺頁異常

一個程序訪問資料的時候,發現沒有,就需要衝磁碟載入
從磁碟的載入有2種可能
1. 原來就沒有載入過
2. 被排程到了交換分割槽上(這個也需要載入)
這個過程就是缺頁異常

1.6 常駐記憶體集和虛擬記憶體集

使用交換分割槽時,不是所有的都能被互動出去的,例如:指令
這種不能被互動出去的就時常駐交換集
虛擬記憶體交換集
可以被交換出去的就是虛擬記憶體集

1.7 IPC機制

因為程序起來以後,它只會以為在物理空記憶體空間,只有自己和核心記憶體空間,程序之間不能發現別的程序,那麼它們之間是怎麼通訊的呢?
同一主機上:
 singal:發訊號的方式
 shm:shared  menmory(使用共享記憶體)
不同主機上
rpc:remote procecure call(遠端呼叫)
socket:

1.8 Linux程序型別

守護程序:daemon,在系統引導過程中啟動的程序,跟終端無關
前臺程序:通過終端啟動的程序,跟終端相關
注意: 也可以把前臺啟動的程序,送往後臺以守護模式進行

1.9 程序狀態

執行態running(需要用到的資料在記憶體中,核心也分配了記憶體給它,並且在執行中)
就緒態(睡眠態):程序該具備的它都有,就差CPU沒有排程他
睡眠態分為2種
1. 可中斷(interrupt able)
2. 不可中斷(uninterrupt able)
停止態:stopped,暫停於記憶體中,不會被排程,除非手動啟之
僵死態:zombie

1.9.1 i/o分為2個過程

1. 某一程序在執行過程中需要載入的資料在記憶體中沒有,於是不得不請求核心,把資料從磁碟裝入到核心的記憶體中
2. 要把核心記憶體中的資料複製一份到程序的記憶體中
所以,程序從發起呼叫開始,要等2段時間
第一段:資料等待從磁碟到核心記憶體中
第二段:再等待核心記憶體中的資料複製一份到程序記憶體中
所以,當資料沒有載入完成,就算把程序叫醒也沒有用,所以這就叫做不可中斷睡眠
把程序排程到CPU上,時間耗盡了,這樣不睡覺也不行,下一次需要排程的時候,能夠立即把他叫醒(因為需要載入的資料已經在記憶體中了),這就叫做可中斷睡眠

第2章 Linux系統上的程序檢視機管理工具

2.1 pstree

檢視程序樹,其餘的選項沒有太大用處

2.2 ps命令

ps命令是怎麼樣能夠檢視程序狀態的?
所有的程序為了能夠讓使用者空間能夠檢視管理程序的相關功能,核心通過一個介面/proc/輸出給使用者,這些相關資訊就是核心引數,這些引數可以分為2類
1. 可設定其值從而調整其值調整核心執行特性的引數/proc/sys
2. 狀態變數:其用於輸出核心中統計資訊和狀態資訊,僅用於檢視
   引數被模擬成檔案系統
      表現形式:/proc/#(#表示pid號)
但是這些目錄先的檔案,如果不是核心機的人員去檢視,根本就看不懂,於是就有了各種各樣的命令,把這些資訊抽取出來,予以顯示給我們看
注意:ps有三種風格的選項
1 UNIX options, which may be grouped and must be preceded by a dash.
2 BSD options, which may be grouped and must not be used with a dash.
3 GNU long options, which are preceded by two dashes.

2.2.1 選項

2.2.1.1 a

顯示所有於終端相關的程序

2.2.1.2 x

所有與終端無關的程序

2.2.1.3 ax

顯示所有程序
其中TTY那一列顯示有的是?號,表示不知道終端是什麼
COMMAND一列有許多中括號的表示的是核心執行緒

2.2.1.4 u

表示以使用者為中心組織

2.2.1.5 常用組合之一aux

VSZ:虛擬記憶體集
RSS:常駐記憶體集
STAT:
   R:running
   S:  interruptable(可中斷睡眠)
   D:uninterruptable(不可中斷睡眠)
   T:stopped
   Z:zmobie
   +: 前臺程序
   l: 多執行緒程序
   <: 高優先順序程序
   N:低優先順序程序
   s: session leader

2.2.1.6 -e和-f [Unix風格]

-e:顯示所有程序
-f:顯示完整格式的程序資訊(就是顯示的全一點)
PID:程序號
PPID: 父程序的程序號
C:CPU的佔用百分比
STIME:啟動時間
TTY:和終端相關
TIME:累積執行時間
CMD:啟動此程序的命令

2.2.1.7 -H

以層級結構顯示程序的相關資訊 

2.2.1.8 -F

psr:運行於哪顆CPU上

2.2.1.9 常用組合之二 ps -eFH

2.2.1.10 常用組合之三ps axo

o自定義要顯示的欄位列表,以逗號分隔(o一定要寫在後面,因為需要帶引數)
常用的欄位
pid,ni,pri,psr,pcpu,stat,comm,tty,ppid,rtprio
ni:nice值
pri:優先順序
rtprio:實時優先順序

2.3 pgrep

只顯示我們感興趣的命令(就是過濾)

2.3.1 選項

2.3.1.1 -U:uid

顯示程序號

2.3.1.2 -t

與指定的終端相關的程序

2.3.1.3 -l顯示程序名

2.3.1.4 -a

顯示完整格式的程序名

2.3.1.5 -p

顯示此程序的子程序,後面接的是程序號,所以可以用ps –aux找到程序號

2.4 top

top- 系統的當前時間
up 執行時長
user 登入當前系統的使用者數
load average: 0.00, 0.01, 0.05 平均負載
   1分鐘,5分鐘,15分鐘
  指的是:平均佇列長度(在CPU上等待執行的佇列的長度)
         通常佇列長度的總數量,不能大於cpu的數量
這一行資訊就是uptime命令
[root@shiyanji ~]# uptime
 16:49:32 up 21:35,  1 user,  load average: 0.00, 0.01, 0.05
us: cpu在使用者態佔用的百分比
sy:cpu在核心態的百分比(控制在30%)
ni:調整nice值後佔用的百分比
id:cpu空閒時間百分比
wa: io的等待時間百分比
hi:硬體中斷百分比
si: 軟體中斷百分比
st:被偷走的百分比(被虛擬化所偷走的時間百分比)
buff/cache:是可以被回收回來使用的,所以真正的空閒空間應該是free+buff/cache

2.5 vmstat

vmstat  [options]  [delay [count]]
procs: 程序
   r:等待執行的程序個數(cpu上等待執行的任務佇列長度)
   b: 不可中斷睡眠態的程序個數(被阻塞的任務佇列長度)
memory: 記憶體
swpd: 交換記憶體的使用總量
free: 空閒的實體記憶體總量
buff:用於buffer的記憶體總量
cache: 用於cache的記憶體總量
swap:
  si:資料進入swap中的資料速率(kb/s)
  so: 資料離開swap的速率(kb/s)
io:
  bi: 從塊裝置讀入資料到系統速率(kb/s)
  bo: 儲存資料到塊裝置的速率(kb/s)
system:
  in: interrupts,中斷速率
  cs: context switch 上下文切換的速率(就是程序被核心排程到cpu上的頻率)

2.5.1 幾秒中顯示一次(一直以動態顯示)

2.5.2 也可以指定只顯示幾次

2秒中只顯示3次,然後就自動退出了

2.5.3 -s 顯示記憶體統計資料