主題進程介紹
一進程相關概念
內核的功用:進程管理、文件系統、網絡功能、內存管理、驅動程序、安全功能等
在操作系統上會運行多個應用程序,應用程序分配多大的內存都由內核實現
程序文件
程序和進程的關系
程序是靜態文件,進程是動態的
程序如果沒有運行那么只是磁盤上的一個文件,只有雙擊的時候才會在系統上運行,並且操作系統會分配內存空間
在內存里面運行,也就是進程。
而進程會占用CPU和內存空間,運行中的程序的一個副本,因為程序可以開啟多個進程。
有些程序是可以運行多個副本的
為了對進程區分,每個進程都有編號的,進程存在生命周期
進程有相關的屬性,比如進程是那個用戶發起的,也就是UID,還有對應的屬主。
注意在國內基本不使用selinux,直接關閉就可以了,而且很多軟件的運行和selinx是沖突的,所以在工作中是禁用selinux的
進程和進程會組合成列表
task struct:Linux內核存儲進程信息的數據結構格式
task list:多個任務的的task struct組成的鏈表
每個進程都有自己的表,記錄了進程的相關屬性
task struct:Linux內核存儲進程信息的數據結構格式
鏈表:
和開發有關的數據結構
進程內存:
Page Frame: 在Linux里面,給進程分配內存空間涉及到了頁框,用存儲頁面數據,存儲Page 4k,也就是內存單位。
和磁盤的存儲類似,磁盤是塊,邏輯卷是PE
給進程分配內存空間的算法:
LRU:Least Recently Used 近期最少使用算法,釋放內存
下圖是內存空間,由很多的小塊組成
假設有數據來了,就會把數據放到第1個小塊里面
如果第2塊數據來了,那么就會把第1塊數據往下壓
如果第2塊數據來了,那么就會把第1塊數據往下壓
如果第3塊數據來了,那么就會把第2塊數據往下壓
一共可以存放8塊數據,如果第9塊數據來了
那么就要淘汰第1塊數據了
變成了這樣的情況:
內存空間相當於磁盤來說是小的
假設情況是這樣的,用戶又要訪問第1塊數據
那么就會把第1塊數據放到最上面,把其他的數據擠下去
假設訪問數據的序列為 4 3 4 2 3 1 4 2
物理塊有3個,則
第1輪 4調入內存 4
第2輪 3調入內存 3 4
第3輪 4調入內存 4 3
第4輪 2調入內存 2 4 3
第5輪 3調入內存 3 2 4
第6輪 1調入內存 1 3 2
第7輪 4調入內存 4 1 3
第8輪 2調入內存 2 4 1
上面的訪問1次數據就激活的情況,還有一種變種,就是訪問兩次或者多次的時候才會激活,把下面的數據放到最上面
知道即可。
實際上這種淘汰機制,LRU算法也是緩存的工作機制。
當數據被訪問的時候就要放到內存的緩存里面,如果數據被頻繁的訪問就會一直在緩存里面放着。
這樣比去磁盤上訪問效率高多了。
如果數據很久都沒有被訪問,那么就會被淘汰了。
[root@centos72 ~]# free total used free shared buff/cache available Mem: 997956 94228 766436 7796 137292 743192 Swap: 2097148 0 2097148
內存給進程分配空間
假設是32位系統,理論上存放的內存空間是2^32,也就是4G內存
應用程序被調到內存里面,他以為擁有4G的所有空間
因為他不知道其他的進程,事實上是操作系統分配了一小塊空間。
4G的空間,1G是操作系統用的,3G是內存給應用程序用的
給應用程序分配的空間會對應物理內存空間
對於應用程序來說,他認為自己獲得的內存空間的地址是從0開始往后編,實際上對應物理內存的某塊空間。
假設內存空間是0——100,其對應物理內存的100——200,就是存在一種映射關系。
上面提到的空間就是物理地址空間和線性地址空間(應用程序眼里的內存空間)
MMU:Memory Management Unit內存管理單元,負責轉換線性和物理地址,CPU的硬件設備。
實際上是表格。
TLB:Translation Lookaside Buffer 翻譯后備緩沖器,用於保存虛擬地址和物理地址映射關系的緩存
IPC: Inter Process Communication進程間通信
進程認為其擁有整個系統內存,也就是認為只有他一個進程。
實際上有很多進程,那么就涉及到了進程之間的通信。
通信機制:
進程在同一台主機:
1signal:信號,比如發送kill
2shm: shared memory共享內存
在內存空間里面,兩個進程獨自運行,彼此之間是不知道對方的存在,更不能直接訪問對方的數據。
所以要共享進程的數據,就要創建共享內存。
相互之間通信了就把數據寫到共享內存里面,從共享內存里面返回數據就可以實現數據的共享了。
3semaphore:信號量,一種計數器
表示對資源的占用。比如我們買火車票,上面顯示有幾張票就說明還有票,如果不能點擊就說明沒有票了。
進程對資源的占用,那么計數器就會顯示為0,其他進程就不能訪問了。
計數器恢復到1其他進程才可以訪問資源。
數據庫有此概念。
當一個用戶在讀取此數據庫的表,另外一個用戶在修改此表,那么就要進行加鎖了。
不同主機:
1socket: IP和端口號
兩個應用程序在不同的機器上,那么就要通過socket來標識應用程序的位置。
socket就是IP地址+TCP/UDP端口號
通過IP找到此機器,通過TCP/UDP端口號找到此機器上唯一的程序。因為每個程序使用唯一的端口號。
2RPC: remote procedure call
假設有兩台機器,當一台機器在運行過程中急需要通過另外一台機器的進程來繼續運行,
那么就會把控制權交給另外一台機器的進程,在另外一台機器運行
那么就調用了另外一台機器的函數,過程等功能。
涉及到開發
3MQ:消息隊列,Kafka,ActiveMQ
兩個進程要完成一些業務,互相進行通信,就要把自己的信息發送到消息隊列里面
並且就像排隊一樣,順序完成
就像我們要去銀行辦事,會先在機器上打印編號,然后坐着等前面的辦好了才可以辦事。
二進程創建
init:第一個進程,和其他進程是父子關系
進程:都由其父進程創建,CoW
fork(), clone()
[root@centos65 ~]# pstree
init─┬─abrt-dump-oops ├─abrtd ├─acpid ├─atd ├─auditd───{auditd} ├─automount───4*[{automount}] ├─crond ├─dbus-daemon───{dbus-daemon} ├─dnsmasq ├─hald─┬─hald-runner─┬─hald-addon-acpi │ │ └─hald-addon-inpu │ └─{hald} ├─ksmtuned───sleep ├─libvirtd───10*[{libvirtd}] ├─master─┬─pickup │ └─qmgr ├─6*[mingetty] ├─rpc.idmapd ├─rpc.mountd ├─rpc.rquotad ├─rpc.statd ├─rpcbind ├─rsyslogd───3*[{rsyslogd}] ├─sshd───sshd───bash───pstree ├─udevd───2*[udevd] └─xinetd
[root@centos72 ~]# pstree
systemd─┬─NetworkManager───2*[{NetworkManager}] ├─VGAuthService ├─agetty ├─auditd───{auditd} ├─crond ├─dbus-daemon───{dbus-daemon} ├─master─┬─pickup │ └─qmgr ├─polkitd───5*[{polkitd}] ├─rsyslogd───2*[{rsyslogd}] ├─sshd───sshd───bash───pstree ├─systemd-journal ├─systemd-logind ├─systemd-udevd ├─tuned───4*[{tuned}] └─vmtoolsd───{vmtoolsd}
cow寫時復制:
父進程開啟之后,會有對應的PID,假設是1000
父進程開啟了一個子進程,假設是2000
如果沒有涉及到數據的更改,還是指向到父進程的內存空間
數據更改了才會開辟獨立的內存空間,讓子進程的進程編號指向新的內存空間
生成子進程會使用到函數fork(), clone()
三進程的基本狀態和轉換
創建狀態:進程在創建時需要申請一個空白PCB(processcontrol block進程控制塊),
相當於內存空間,向其中填寫控制和管理進程的信息,完成資源分配。
如果創建工作無法完成,比如資源無法滿足,就無法被調度運行,把此時進程所處狀態稱為創建狀態。
就緒狀態:進程已經准備好,已分配到所需資源,只要分配到CPU就能夠立即運行。
根據CPU的調度運行,其他進程的資源可以釋放,那么CPU就可以讓處於就緒的進程運行。
如果進程什么都沒有做,占用CPU沒有什么意義的。
所以時間片到了之后就會釋放。
時間片就是把CPU的運行時間切割成很多小片。
如果時間片到了,但是進程沒有執行完,那么就會把當前的狀態保留下來。
然后把CPU釋放,這樣就可以運行其他進程了。達到了時間片有會運行之前還沒有運行完的進程。
時間片是幾毫秒的,所以我們感覺不到進程在切換,好像很多進程同時運行。
如果遇到了急需要運行的進程,那么即使時間片沒到,也會釋放其他進程的CPU
CPU就要人一樣,同一時間只能做一件事,但是因為切換太快了,所以感覺在做好幾件事。
如果CPU是多內核的,那么就像多個人同時做事,比如4核就是4個內核同時做事,這樣效率就很高了。
執行狀態:進程處於就緒狀態被調度后,進程進入執行狀態。
阻塞狀態:正在執行的進程由於某些事件(I/O請求,申請緩存區失敗)而暫時無法運行,進程受到阻塞。
在滿足請求時進入就緒狀態等待系統調用。
在執行的時候要讀取磁盤上的數據,那么就會發送指令給CPU,說要讀取磁盤
但是磁盤的運行速度是很慢的,那么CPU的進程就處於就阻塞了,CPU不會阻塞,可以為其他程序服務
I/O結束之后就再次進入到了就緒狀態,那么CPU就會再次分配時間片給此進程了。
終止狀態:進程結束,或出現錯誤,或被系統終止,進入終止狀態。無法再執行
四進程優先級
如果遇到了急需要運行的進程,那么即使時間片沒到,也會釋放其他進程的CPU,涉及到了優先級。
進程優先級:
1系統優先級:數字越小,優先級越高
0-139(CentOS4,5)各有140個運行隊列和過期隊列
0-98,99(CentOS6)
2實時優先級: 99-0 值最大優先級最高
3nice值:-20到19,對應系統優先級100-139或99
假設有2000個進程要運行,並且優先級就不同,理論上要運行優先級最高的進程。
而且要排序才知道那個進程的優先級高。
如果優先級都一樣,那么有兩種策略,一是先來的先運行,二是輪流執行
有140個優先級就排成140個隊列
假設100優先級有好幾個進程在運行,比如A,B,C;假設101優先級有好幾個進程在運行,比如D,E,F
數字越小,優先級越高,那么就先運行100優先級里面的A進程。
假設A進程要1個小時才可以執行完成,那么A進程運行5毫秒之后,就必須要釋放CPU
那么A進程會被遷移到100優先級的隊列,但是是過期隊列。而之前的100優先級隊列是運行隊列。
此時運行隊列就沒有A進程了。
A運行5毫秒之后就輪到B進程運行了,運行了5毫秒之后,B沒有執行完就和A進程,被放到過期隊列里面了。
以此類推,C進程和A,B一樣
現在100優先級的過期隊列和運行隊列對調
也就是過期隊列變成了運行隊列,運行隊列變成了過期隊列。
此時A進程又開始運行了,如果運行5毫秒沒有完成,那么就和之前一樣,被加入到了過期隊列。
100優先級的其他進程也是這樣,直到100優先級的所有進程都執行完成了,那么就可以運行101優先級的進程。
和100優先級一樣,101也有兩個隊列,運行隊列和過期隊列
進程再多也只有140個隊列。所以優先級結合隊列比較優先級效率更高。
Big O:時間復雜度,用時和規模的關系,一共有下面5種情況:
O(1), O(logn), O(n)線性, O(n^2)拋物線, O(2^n)
比如有1000個進程,就是規模。
不管規模多大花的時間都一樣是最好的。對應的是O(1)
O(logn),增長不是很快,但是會超過恆定值的
O(n)線性
隨着規模越大,花的時間越多
O(n^2)拋物線,比線性上漲的還快
O(2^n)指數型增長
做開發涉及到了很多的算法
優先級
下圖顯示了4種優先級,分別是系統優先級,實時優先級,nice優先級,top命令的優先級
圖片的位置是對應的,比如系統優先級和實時優先級相反,0對應99
系統優先級:數字越小,優先級越高
0-139(CentOS4,5)
各有140個運行隊列和過期隊列
0-98,99(CentOS6)
實時優先級: 99-0 值最大優先級最高
nice值:-20到19,對應系統優先級100-139或99
五進程狀態
Linux內核:搶占式多任務,也就是計算機是根據時間片分配CPU資源的
進程類型:
守護進程: daemon,在系統引導過程中啟動的進程,和終端無關進程
前台進程:跟終端相關,通過終端啟動的進程
注意:兩者可相互轉化
進程狀態:
運行態:running
就緒態:ready
睡眠態:
可中斷:interruptable
不可中斷:uninterruptable
停止態:stopped,暫停於內存,但不會被調度,除非手動啟動
僵死態:zombie,結束進程,父進程結束前,子進程不關閉