Linux基礎(一)

Linux基礎

用戶模式和內核模式

MS-DOS等操作系統在單一的CPU模式下運行,但是一些類Unix的操作系統則使用了雙模式,可以有效地實現時間共享。在Linux機器上,CPU要麼處於受信任的內核模式,要麼處於受限制的用戶模式。除了內核本身處於內核模式以外,所有的用戶進程都運行在用戶模式之中。

內核模式的代碼可以無限制地訪問所有處理器指令集以及全部內存和I/O空間。如果用戶模式的進程要享有此特權,它必須通過系統調用向設備驅動程序或其他內核模式的代碼發出請求。另外,用戶模式的代碼允許發生缺頁,而內核模式的代碼則不允許。

在2.4和更早的內核中,僅僅用戶模式的進程可以被上下文切換出局,由其他進程搶佔。除非發生以下兩種情況,否則內核模式代碼可以一直獨佔CPU:

(1) 它自願放棄CPU;

(2) 發生中斷或異常。

2.6內核引入了內核搶佔,大多數內核模式的代碼也可以被搶佔。

內核空間和用戶空間

現在操作系統都是採用虛擬存儲器,那麼對32位操作系統而言,它的尋址空間(虛擬存儲空間)爲4G(2的32次方)。操作系統的核心是內核,獨立於普通的應用程序,可以訪問受保護的內存空間,也有訪問底層硬件設備的所有權限。爲了保證用戶進程不能直接操作內核(kernel),保證內核的安全,操作系統將虛擬空間劃分爲兩部分,一部分爲內核空間,一部分爲用戶空間。針對linux操作系統而言,將最高的1G字節(從虛擬地址0xC0000000到0xFFFFFFFF),供內核使用,稱爲內核空間,而將較低的3G字節(從虛擬地址0×00000000到0xBFFFFFFF),供各個進程使用,稱爲用戶空間。

32位系統用戶進程最大可以訪問3GB,內核代碼可以訪問所有物理內存。

64位系統用戶進程最大可以訪問超過512GB,內核代碼可以訪問所有物理內存。

進程和線程

參考文檔:https://my.oschina.net/cnyinlinux/blog/422207(寫的很好)

進程的初始化

第一個被創造出來的進程是0號進程,這個進程在操作系統層面是不可見的,但它存在着。0號進程完成了操作系統的功能加載與初期設定,然後它創造了1號進程(init),這個1號進程就是操作系統的“耶穌”。1號進程是上帝派來管理整個操作系統的,所以在用pstree查看進程樹可知,1號進程位於樹根。再之後,系統的很多管理程序都以進程身份被1號進程創造出來,還創造了與人類溝通的橋樑——shell。從那之後,人類可以跟操作系統進行交流,可以編寫程序,可以執行任務。。。

而這一切,都是基於進程的。每一個任務(進程)被創建時,系統會爲他分配存儲空間等必要資源,然後在內核管理區爲該進程創建管理節點,以便後來控制和調度該任務的執行。

進程真正進入執行階段,還需要獲得CPU的使用權,這一切都是操作系統掌管着,也就是所謂的調度,在各種條件滿足(資源與CPU使用權均獲得)的情況下,啓動進程的執行過程。

除CPU而外,一個很重要的資源就是存儲器了,系統會爲每個進程分配獨有的存儲空間,當然包括它特別需要的別的資源,比如寫入時外部設備是可使用狀態等等。

進程和線程

進程,是計算機中的程序關於某數據集合上的一次運行活動,是系統進行資源分配和調度的基本單位,是操作系統結構的基礎。它的執行需要系統分配資源創建實體之後,才能進行。

隨着技術發展,在執行一些細小任務時,本身無需分配單獨資源時(多個任務共享同一組資源即可,比如所有子進程共享父進程的資源),進程的實現機制依然會繁瑣的將資源分割,這樣造成浪費,而且還消耗時間。後來就有了專門的多任務技術被創造出來——線程。

異同點:

  • 二者的相同點:

在系統層面,都可以通過技術手段實現二者的控制。而且二者所具有的狀態都非常相似。而且,在多任務程序中,子進程(子線程)的調度一般與父進程(父線程)平等競爭。

  • 實現方式的差異:

進程是資源分配的基本單位,線程是調度的基本單位。進程的個體間是完全獨立的,而線程間是彼此依存的。多進程環境中,任何一個進程的終止,不會影響到其他進程。而多線程環境中,父線程終止,全部子線程被迫終止(沒有了資源)。而任何一個子線程終止一般不會影響其他線程,除非子線程執行了exit()系統調用。任何一個子線程執行exit(),全部線程同時滅亡。

  • 多任務程序設計模式的區別:

由於進程間是獨立的,所以在設計多進程程序時,需要做到資源獨立管理時就有了天然優勢,而線程就顯得麻煩多了。多進程環境間完全獨立,要實現通信的話就得采用進程間的通信方式,它們通常都是耗時間的。而線程則不用任何手段數據就是共享的。當然多個子線程在同時執行寫入操作時需要實現互斥,否則數據就寫“髒”了。

  • 實體間(進程間,線程間,進線程間)通信方式的不同:

進程間的通信方式有這樣幾種:

  1. 共享內存
  2. 消息隊列
  3. 信號量
  4. 有名管道
  5. 無名管道
  6. 信號
  7. 文件
  8. socket

線程間的通信方式上述進程間的方式都可沿用,且還有自己獨特的幾種:

  1. 互斥量
  2. 自旋鎖
  3. 條件變量
  4. 讀寫鎖
  5. 線程信號
  6. 全局變量

值得注意的是,線程間通信用的信號不能採用進程間的信號,因爲信號是基於進程爲單位的,而線程是共屬於同一進程空間的。故而要採用線程信號。

  • 控制方式的異同:

進程與線程的身份標示ID管理方式不一樣,進程的ID爲pid_t類型,實際爲一個int型的變量(也就是說是有限的)

線程的ID是一個long型變量,它的範圍大得多,管理方式也不一樣。線程ID一般在本進程空間內作用就可以了,當然系統在管理線程時也需要記錄其信息。其方式是,在內核創建一個內核態線程與之對應,也就是說每一個用戶創建的線程都有一個內核態線程對應。但這種對應關係不是一對一,而是多對一的關係,也就是一個內核態線程可以對應着多個用戶級線程。

  • 資源管理方式的異同

進程本身是資源分配的基本單位,因而它的資源都是獨立的,如果有多進程間的共享資源,就要用到進程間的通信方式了,比如共享內存。共享數據就放在共享內存去,大家都可以訪問,爲保證數據寫入的安全,加上信號量一同使用。一般而言,共享內存都是和信號量一起使用。消息隊列則不同,由於消息的收發是原子操作,因而自動實現了互斥,單獨使用就是安全的。

線程間要使用共享資源不需要用共享內存,直接使用全局變量即可,或者malloc()動態申請內存。顯得方便直接。而且互斥使用的是同一進程空間內的互斥量,所以效率上也有優勢。

  • 進程池與線程池的技術實現差別

具體略。

用戶模式下進程間通信

  1. 管道Pipe:管道可用於具有親緣關係進程間的通信,允許一個進程和另一個與它有共同祖先的進程之間進行通信。
  2. 命名管道named pipe:命名管道克服了管道沒有名字的限制,因此,除具有管道所具有的功能外,它還允許無親緣關係進程間的通信。命名管道在文件系統中有對應的文件名。命名管道通過命令mkfifo或系統調用mkfifo來創建。
  3. 信號Signal:信號是比較複雜的通信方式,用於通知接受進程有某種事件發生,除了用於進程間通信外,進程還可以發送信號給進程本身;linux除了支持Unix早期信號語義函數sigal外,還支持語義符合Posix.1標準的信號函數sigaction實際上,該函數是基於BSD的,BSD爲了實現可靠信號機制,又能夠統一對外接口,用sigaction函數重新實現了signal函數)。
  4. 消息Message隊列:消息隊列是消息的鏈接表,包括Posix消息隊列system V消息隊列。有足夠權限的進程可以向隊列中添加消息,被賦予讀權限的進程則可以讀走隊列中的消息。消息隊列克服了信號承載信息量少,管道只能承載無格式字節流以及緩衝區大小受限等缺
  5. 共享內存:使得多個進程可以訪問同一塊內存空間,是最快的可用IPC形式。是針對其他通信機制運行效率較低而設計的。往往與其它通信機制,如信號量結合使用,來達到進程間的同步及互斥。
  6. 信號量semaphore:主要作爲進程間以及同一進程不同線程之間的同步手段。
  7. 套接字Socket:更爲一般的進程間通信機制,可用於不同機器之間的進程間通信。起初是由Unix系統的BSD分支開發出來的,但現在一般可以移植到其它類Unix系統上:Linux和System V的變種都支持套接字。

進程的切換過程

爲了控制進程的執行,內核必須有能力掛起正在CPU上運行的進程,並恢復以前掛起的某個進程的執行。即從用戶態(較低的3G字節)切換到內核態(最高的1G字節),非常消耗系統資源。

過程如下:

  • 保存處理機上下文,包括程序計數器和其他寄存器。
  • 更新PCB信息。
  • 把進程的PCB移入相應的隊列,如就緒、在某事件阻塞等隊列。
  • 選擇另一個進程執行,並更新其PCB。
  • 更新內存管理的數據結構。
  • 恢復處理機上下文。

IO模型

IO的本質是socket的讀取,數據先拷貝到內核的緩衝區中,然後拷貝到應用程序的地址空間(進程)。linux下提供5種IO模型。

同步和異步

同步與異步同步和異步關注的是消息通信機制 (synchronous communication/ asynchronous communication)所謂同步,就是在發出一個調用時,在沒有得到結果之前,該調用就不返回。但是一旦調用返回,就得到返回值了。換句話說,就是由調用者主動等待這個調用的結果。

而異步則是相反,調用在發出之後,這個調用就直接返回了,所以沒有返回結果。換句話說,當一個異步過程調用發出後,調用者不會立刻得到結果。而是在調用發出後,被調用者通過狀態、通知來通知調用者,或通過回調函數處理這個調用。

阻塞和非阻塞關注的是程序在等待調用結果(消息,返回值)時的狀態。

阻塞調用是指調用結果返回之前,當前線程會被掛起。調用線程只有在得到結果之後纔會返回。非阻塞調用指在不能立刻得到結果之前,該調用不會阻塞當前線程。

說白了,同步和異步指的是幹這個事情的結果是我主動去問(同步),還是事情完事兒後直接通知我(異步)。

阻塞和非阻塞指的是幹這個事兒的時候能不能幹別的事兒,阻塞就是不能幹別的事兒,非阻塞指的是可以繼續幹下面的事兒。

BIO(blocking IO):同步阻塞 I/O

從上圖可以看到在整個過程中,當用戶進程進行系統調用時,內核就開始了I/O的第一個階段,準備數據到緩衝區中,當數據都準備完成後,則將數據從內核緩衝區中拷貝到用戶進程的內存中,這時用戶進程才解除block的狀態重新運行。

特點

  • Blocking I/O是在I/O執行的兩個階段都被block了。
  • 能夠及時返回數據,無延遲
  • 性能下降

NIO(nonblocking IO):同步非阻塞 I/O

從上圖可以看到在I/O執行的兩個階段中,用戶進程只有在第二個階段被阻塞了,而第一個階段沒有阻塞,但是在第一個階段中,用戶進程需要盲等,不停的去輪詢內核,看數據是否準備好了。

特點:

  • nonblocking I/O是在I/O執行的第二個階段(數據複製)被block了,而第一個階段並未阻塞(數據準備)。
  • 拷貝數據的整個過程,進程仍然是阻塞的
  • 需要不斷詢問數據是否準備好了
  • 能夠在等待任務完成的過程中處理其他事件
  • 由於需要輪詢,所以延遲會增加

多路複用IO( IO multiplexing)(異步阻塞)

從上圖可以看到在I/O複用模型中,由於同步非阻塞方式需要不斷主動輪詢,輪詢佔據了很大一部分過程,輪詢會消耗大量的CPU時間,而 “後臺” 可能有多個任務在同時進行。

IO多路複用是阻塞在select,epoll這樣的系統調用之上,而沒有阻塞在真正的I/O系統調用如recvfrom之上。怎麼理解呢?

應用程序要執行read操作,因此調用一個system call,這個system call被傳遞給了kernel。但在應用程序這邊,它調用system call之後,並不等待kernel的返回結果而是立即返回,雖然立即返回的調用函數是一個異步的方式,但應用程序會被像select()、poll和epoll等具有複用多個文件描述符的函數阻塞住,一直等到這個system call有結果返回了,再通知應用程序。也就是說,“在這種模型中,IO函數是非阻塞的,使用阻塞 select、poll、epoll系統調用來確定一個 或多個IO 描述符何時能操作。”所以,從IO操作的實際效果來看,異步阻塞IO和第一種同步阻塞IO是一樣的,應用程序都是一直等到IO操作成功之後(數據已經被寫入或者讀取),纔開始進行下面的工作。不同點在於異步阻塞IO用一個select函數可以爲多個描述符提供通知,提高了併發性。

舉個例子:假如有一萬個併發的read請求,但是網絡上仍然沒有數據,此時這一萬個read會同時各自阻塞,現在用select、poll、epoll這樣的函數來專門負責阻塞同時監聽這一萬個請求的狀態,一旦有數據到達了就負責通知,這樣就將之前一萬個的各自爲戰的等待與阻塞轉爲一個專門的函數來負責與管理。與此同時,異步阻塞IO和第二種同步非阻塞IO的區別在於:同步非阻塞IO是需要應用程序主動地循環去詢問是否有操作數據可操作,而異步阻塞IO是通過像select和poll等這樣的IO多路複用函數來同時檢測多個事件句柄來告知應用程序是否可以有數據操作。

特點

  • select/poll調用後會阻塞進程,但可以同時阻塞多個IO事件操作(文件描述符),有數據可讀或可寫(就緒事件),就通知用戶進程。
  • select 需要每次註冊事件(輪詢),而epoll不需要每次註冊事件(沒有輪詢,回調函數)
  • IO多路複用阻塞在select/epoll的系統調用之上的,而真正的IO系統調用如recvfrom是非阻塞的。

信號驅動I/O( signal driven IO)

應用程序提交read請求的system call,然後,kernel開始處理相應的IO操作,而同時,應用程序並不等kernel返回響應,就會開始執行其他的處理操作(應用程序沒有被IO操作所阻塞)。當kernel執行完畢,返回read的響應,就會產生一個信號或執行一個基於線程的回調函數來完成這次 IO 處理過程。

從理論上說,阻塞IO、IO複用和信號驅動的IO都是同步IO模型。因爲在這三種模型中,IO的讀寫操作都是在IO事件發生之後由應用程序來完成。而LINUX規範所定義的異步IO模型則不同。對異步IO而言,內核用戶可以直接對IO執行讀寫操作,這些操作告訴內核用戶讀寫緩衝區的位置,以及IO操作完成後內核通知應用程序的方式。異步IO讀寫操作總是立即返回,而不論IO是否阻塞的,因爲真正的讀寫操作已經由內核接管。也就是說,同步IO模型要求用戶代碼自行執行IO操作(將數據從內核緩衝區讀入用戶緩衝區,或將數據從用戶緩衝區寫入內核緩衝區),而異步IO機制則是由內核來執行IO操作(數據在內核緩衝區和用戶緩衝區之間的移動是由內核在後臺完成的)。你可以這樣認爲,同步IO嚮應用程序通知的是IO就緒事件,而異步IO嚮應用程序通知的是IO完成事件。linux環境下,aio.h頭文件中定義的函數提供了對異步IO的支持。

異步 I/O(asynchronous IO)

異步IO與上面的異步概念是一樣的, 當一個異步過程調用發出後,調用者不能立刻得到結果,實際處理這個調用的函數在完成後,通過狀態、通知和回調來通知調用者的輸入輸出操作。異步IO的工作機制是:告知內核啓動某個操作,並讓內核在整個操作完成後通知我們,這種模型與信號驅動的IO區別在於,信號驅動IO是由內核通知我們何時可以啓動一個IO操作,這個IO操作由用戶自定義的信號函數來實現,而異步IO模型是由內核告知我們IO操作何時完成。爲了實現異步IO,專門定義了一套以aio開頭的API,如:aio_read.

拿食堂打飯舉例:

  • 同步阻塞IO: 自己得排隊,排隊期間不能幹別的,輪到自己後自己打飯。
  •  同步非阻塞IO: 不用排隊了,食堂給分一個號,可以乾點兒別的,但是自己需要不斷去窗口詢問是否輪到自己,輪到自己後自己打飯。
  • 多路複用IO: 不用排隊了,食堂給分一個號,可以乾點兒別的,一個專門的人幫我問是否輪到自己(還是需要問食堂),輪到自己後自己去打飯。
  • 信號驅動:不用排隊了,食堂給分一個號,可以乾點兒別的,飯好了食堂發個消息告訴你好了,然後自己去打飯。
  • 異步非阻塞:領導給食堂打了個電話,食堂把飯打好後直接給領導送過去了。(注:前四種都得自己打飯,異步非阻塞不需要你打飯,食堂給把飯打好了,因此從這個意義上,只有這種是真正意義上的異步)。

select,poll,epoll

一個進程可以同時對多個客戶請求進行服務。也就是說IO複用的“介質”是進程(準確的說複用的是select和poll,因爲進程也是靠調用select和poll來實現的),複用一個進程(select和poll)來對多個IO進行服務,雖然客戶端發來的IO是併發的但是IO所需的讀寫數據多數情況下是沒有準備好的,因此就可以利用一個函數(select和poll)來監聽IO所需的這些數據的狀態,一旦IO有數據可以進行讀寫了,進程就來對這樣的IO進行服務。

select,poll,epoll都是IO多路複用的機制,IO多路複用就是通過一種機制,可以監視多個描述符,一旦某個描述符就緒(一般是讀就緒或者寫就緒),能夠通知應用程序進行相應的讀寫操作。但select,poll,epoll本質上都是同步IO,因爲他們都需要在讀寫事件就緒後自己負責進行讀寫,也就是說這個讀寫過程是阻塞的,而異步IO則無需自己負責進行讀寫,異步IO的實現會負責把數據從內核拷貝到用戶空間。三者的原型如下所示:

  • int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
  • int poll(struct pollfd *fds, nfds_t nfds, int timeout);
  • int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

select

select的調用步驟如下:

  • 使用copy_from_user從用戶空間拷貝fdset到內核空間
  • 註冊回調函數__pollwait
  • 遍歷所有fd,調用其對應的poll方法(對於socket,這個poll方法是sock_poll,sock_poll根據情況會調用到tcp_poll,udp_poll或者datagram_poll)
  • 以tcp_poll爲例,其核心實現就是__pollwait,也就是上面註冊的回調函數。
  • __pollwait的主要工作就是把current(當前進程)掛到設備的等待隊列中,不同的設備有不同的等待隊列,對於tcp_poll 來說,其等待隊列是sk->sk_sleep(注意把進程掛到等待隊列中並不代表進程已經睡眠了)。在設備收到一條消息(網絡設備)或填寫完文件數 據(磁盤設備)後,會喚醒設備等待隊列上睡眠的進程,這時current便被喚醒了。
  • poll方法返回時會返回一個描述讀寫操作是否就緒的mask掩碼,根據這個mask掩碼給fd_set賦值。
  • 如果遍歷完所有的fd,還沒有返回一個可讀寫的mask掩碼,則會調用schedule_timeout是調用select的進程(也就是 current)進入睡眠。當設備驅動發生自身資源可讀寫後,會喚醒其等待隊列上睡眠的進程。如果超過一定的超時時間(schedule_timeout 指定),還是沒人喚醒,則調用select的進程會重新被喚醒獲得CPU,進而重新遍歷fd,判斷有沒有就緒的fd。
  • 把fd_set從內核空間拷貝到用戶空間。

select缺點:

  1. 每次調用select,都需要把fd集合從用戶態拷貝到內核態,這個開銷在fd很多時會很大
  2. 同時每次調用select都需要在內核遍歷傳遞進來的所有fd,這個開銷在fd很多時也很大
  3. select支持的文件描述符數量太小了,默認是1024

poll

poll與select不同,通過一個pollfd數組向內核傳遞需要關注的事件,故沒有描述符個數的限制,pollfd中的events字段和revents分別用於標示關注的事件和發生的事件,故pollfd數組只需要被初始化一次。

poll的實現機制與select類似,其對應內核中的sys_poll,只不過poll向內核傳遞pollfd數組,然後對pollfd中的每個描述符進行poll,相比處理fdset來說,poll效率更高。poll返回後,需要對pollfd中的每個元素檢查其revents值,來得指事件是否發生。

poll本質上和select沒有區別,它將用戶傳入的數組拷貝到內核空間,然後查詢每個fd對應的設備狀態,如果設備就緒則在設備等待隊列中加入一項並繼續遍歷,如果遍歷完所有fd後沒有發現就緒設備,則掛起當前進程,直到設備就緒或者主動超時,被喚醒後它又要再次遍歷fd。這個過程經歷了多次無謂的遍歷。

它沒有最大連接數的限制,原因是它是基於鏈表來存儲的,但是同樣有一個缺點:

1、大量的fd的數組被整體複製於用戶態和內核地址空間之間,而不管這樣的複製是不是有意義。                   

2、poll還有一個特點是“水平觸發”,如果報告了fd後,沒有被處理,那麼下次poll時會再次報告該fd

epoll

通知機制和輪詢機制:

  • 通知機制,就是當事件發生的時候,去通知他
  • 通知機制的反面,就是輪詢機制

簡單來說,epoll是一種當文件描述符的內核緩衝區非空的時候,發出可讀信號進行通知,當寫緩衝區不滿的時候,發出可寫信號通知的機制。

epoll有EPOLLLT和EPOLLET兩種觸發模式(水平觸發和邊緣觸發),LT是默認的模式,ET是“高速”模式。LT模式下,只要這個fd還有數據可讀,每次 epoll_wait都會返回它的事件,提醒用戶程序去操作,而在ET(邊緣觸發)模式中,它只會提示一次,直到下次再有數據流入之前都不會再提示了,無 論fd中是否還有數據可讀。所以在ET模式下,read一個fd的時候一定要把它的buffer讀光,也就是說一直讀到read的返回值小於請求值,或者 遇到EAGAIN錯誤。還有一個特點是,epoll使用“事件”的就緒通知方式,通過epoll_ctl註冊fd,一旦該fd就緒,內核就會採用類似callback的回調機制來激活該fd,epoll_wait便可以收到通知。

水平觸發(level-trggered):

  • 只要文件描述符關聯的讀內核緩衝區非空,有數據可以讀取,就一直髮出可讀信號進行通知,
  • 當文件描述符關聯的內核寫緩衝區不滿,有空間可以寫入,就一直髮出可寫信號進行通知

邊緣觸發(edge-triggered)

  • 當文件描述符關聯的讀內核緩衝區由空轉化爲非空的時候,則發出可讀信號進行通知,
  • 當文件描述符關聯的內核寫緩衝區由滿轉化爲不滿的時候,則發出可寫信號進行通知

舉例:

  1. 讀緩衝區剛開始是空的
  2. 讀緩衝區寫入2KB數據
  3. 水平觸發和邊緣觸發模式此時都會發出可讀信號
  4. 收到信號通知後,讀取了1kb的數據,讀緩衝區還剩餘1KB數據
  5. 水平觸發會再次進行通知,而邊緣觸發不會再進行通知。

epoll三個函數方法:

  • epoll_create:創建epoll實例,會創建所需要的紅黑樹,以及就緒鏈表,以及代表epoll實例的文件句柄
  • epoll_ctl:添加,修改,或者刪除 註冊到epoll實例中的文件描述符上的監控事件
  • epoll_wait:等待註冊的事件發生,返回事件的數目,並將觸發的事件寫入events數組中。

總結:

  1. poll 和 select 的實現非常類似,本質上的區別就是存放 fd 集合的數據結構不一樣。select 在一個進程內可以維持最多 1024 個連接,poll 在此基礎上做了加強,可以維持任意數量的連接。但 select 和 poll 方式有一個很大的問題就是,我們不難看出來 select 是通過輪訓的方式來查找是否可讀或者可寫,打個比方,如果同時有100萬個連接都沒有斷開,而只有一個客戶端發送了數據,所以這裏它還是需要循環這麼多次,造成資源浪費。
  2. select,poll實現需要自己不斷輪詢所有fd集合,直到設備就緒,期間可能要睡眠和喚醒多次交替。而epoll其實也需要調用 epoll_wait不斷輪詢就緒鏈表,期間也可能多次睡眠和喚醒交替,但是它是設備就緒時,調用回調函數,把就緒fd放入就緒鏈表中,並喚醒在 epoll_wait中進入睡眠的進程。雖然都要睡眠和交替,但是select和poll在“醒着”的時候要遍歷整個fd集合,而epoll在“醒着”的 時候只要判斷一下就緒鏈表是否爲空就行了,這節省了大量的CPU時間,這就是回調機制帶來的性能提升。
  3. select,poll每次調用都要把fd集合從用戶態往內核態拷貝一次,並且要把current往設備等待隊列中掛一次,而epoll只要 一次拷貝,而且把current往等待隊列上掛也只掛一次(在epoll_wait的開始,注意這裏的等待隊列並不是設備等待隊列,只是一個epoll內 部定義的等待隊列),這也能節省不少的開銷。

內核參數優化

修改打開文件數

修改文件地址/etc/security/limits.conf:

vi /etc/security/limits.conf
* soft nproc 11000
* hard nproc 11000
* soft nofile 655350
* hard nofile 655350

sed -i '/# End of file/ i\*       soft    nofile          65535' /etc/security/limits.conf
sed -i '/# End of file/ i\*       hard    nofile          65535' /etc/security/limits.conf

sed -i 's/*          soft    nproc     1024/*          soft    nproc     65535/g' /etc/security/limits.d/90-nproc.conf

tcp相關

下列文件所在目錄:/proc/sys/net/ipv4/

參數 默認值 建議值 說明
net.ipv4.tcp_syn_retries
5 1 對於一個新建連接,內核要發送多少個 SYN 連接請求才決定放棄。不應該大於255,默認值是5,對應於180秒左右時間。。(對於大負載而物理通信良好的網絡而言,這個值偏高,可修改爲2.這個值僅僅是針對對外的連接,對進來的連接,是由tcp_retries1決定的)
net.ipv4.tcp_synack_retries
5 1 對於遠端的連接請求SYN,內核會發送SYN + ACK數據報,以確認收到上一個 SYN連接請求包。這是所謂的三次握手( threeway handshake)機制的第二個步驟。這裏決定內核在放棄連接之前所送出的 SYN+ACK 數目。不應該大於255,默認值是5,對應於180秒左右時間。
net.ipv4.tcp_keepalive_time
7200 600

TCP發送keepalive探測消息的間隔時間(秒),用於確認TCP連接是否有效。

防止兩邊建立連接但不發送數據的攻擊。

net.ipv4.tcp_keepalive_probes
9 3 TCP發送keepalive探測消息的間隔時間(秒),用於確認TCP連接是否有效。
net.ipv4.tcp_keepalive_intvl

75

15

探測消息未獲得響應時,重發該消息的間隔時間(秒)。默認值爲75秒。 (對於普通應用來說,這個值有一些偏大,可以根據需要改小.特別是web類服務器需要改小該值,15是個比較合適的值)

net.ipv4.tcp_retries2

15

5

在丟棄激活(已建立通訊狀況)的TCP連接之前﹐需要進行多少次重試。默認值爲15,根據RTO的值來決定,相當於13-30分鐘(RFC1122規定,必須大於100秒).(這個值根據目前的網絡設置,可以適當地改小,我的網絡內修改爲了5)

net.ipv4.tcp_fin_timeout

60

2

對於本端斷開的socket連接,TCP保持在FIN-WAIT-2狀態的時間。對方可能會斷開連接或一直不結束連接或不可預料的進程死亡。默認值爲 60 秒。

net.ipv4.tcp_max_tw_buckets

180000

36000

系統在同時所處理的最大 timewait sockets 數目。如果超過此數的話﹐time-wait socket 會被立即砍除並且顯示警告信息。之所以要設定這個限制﹐純粹爲了抵禦那些簡單的 DoS 攻擊﹐不過﹐如果網絡條件需要比默認值更多﹐則可以提高它(或許還要增加內存)。(事實上做NAT的時候最好可以適當地增加該值)

net.ipv4.tcp_tw_recycle
0 1 打開快速 TIME-WAIT sockets 回收。除非得到技術專家的建議或要求﹐請不要隨意修改這個值。(做NAT的時候,建議打開它)
net.ipv4.tcp_tw_reuse

0

1

表示是否允許重新應用處於TIME-WAIT狀態的socket用於新的TCP連接(這個對快速重啓動某些服務,而啓動後提示端口已經被使用的情形非常有幫助)

net.ipv4.tcp_max_orphans

8192

32768

系統所能處理不屬於任何進程的TCP sockets最大數量。假如超過這個數量﹐那麼不屬於任何進程的連接會被立即reset,並同時顯示警告信息。之所以要設定這個限制﹐純粹爲了抵禦那些簡單的 DoS 攻擊﹐千萬不要依賴這個或是人爲的降低這個限制。如果內存大更應該增加這個值。(這個值Redhat AS版本中設置爲32768,但是很多防火牆修改的時候,建議該值修改爲2000)

net.ipv4.tcp_syncookies

0

1

只有在內核編譯時選擇了CONFIG_SYNCOOKIES時纔會發生作用。當出現syn等候隊列出現溢出時象對方發送syncookies。目的是爲了防止syn flood攻擊。

net.ipv4.tcp_max_syn_backlog

1024

16384

對於那些依然還未獲得客戶端確認的連接請求﹐需要保存在隊列中最大數目。對於超過 128Mb 內存的系統﹐默認值是 1024 ﹐低於 128Mb 的則爲 128。如果服務器經常出現過載﹐可以嘗試增加這個數字。警告﹗假如您將此值設爲大於 1024﹐最好修改include/net/tcp.h裏面的TCP_SYNQ_HSIZE﹐以保持TCP_SYNQ_HSIZE*16(SYN Flood攻擊利用TCP協議散佈握手的缺陷,僞造虛假源IP地址發送大量TCP-SYN半打開連接到目標系統,最終導致目標系統Socket隊列資源耗盡而無法接受新的連接。爲了應付這種攻擊,現代Unix系統中普遍採用多連接隊列處理的方式來緩衝(而不是解決)這種攻擊,是用一個基本隊列處理正常的完全連接應用(Connect()和Accept() ),是用另一個隊列單獨存放半打開連接。這種雙隊列處理方式和其他一些系統內核措施(例如Syn-Cookies/Caches)聯合應用時,能夠比較有效的緩解小規模的SYN Flood攻擊(事實證明)

net.ipv4.tcp_wmem

4096

16384

131072

8192

131072

16777216

發送緩存設置

min:爲TCP socket預留用於發送緩衝的內存最小值。每個tcp socket都可以在建議以後都可以使用它。默認值爲4096(4K)。

default:爲TCP socket預留用於發送緩衝的內存數量,默認情況下該值會影響其它協議使用的net.core.wmem_default 值,一般要低於net.core.wmem_default的值。默認值爲16384(16K)。

max: 用於TCP socket發送緩衝的內存最大值。該值不會影響net.core.wmem_max,"靜態"選擇參數SO_SNDBUF則不受該值影響。默認值爲131072(128K)。(對於服務器而言,增加這個參數的值對於發送數據很有幫助,在我的網絡環境中,修改爲了51200 131072 204800)

net.ipv4.tcp_rmem

4096

87380

174760

32768

131072

16777216

接收緩存設置

同tcp_wmem

net.ipv4.tcp_mem

根據內存計算

786432

1048576 1572864

low:當TCP使用了低於該值的內存頁面數時,TCP不會考慮釋放內存。即低於此值沒有內存壓力。(理想情況下,這個值應與指定給 tcp_wmem 的第 2 個值相匹配 - 這第 2 個值表明,最大頁面大小乘以最大併發請求數除以頁大小 (131072 * 300 / 4096)。 )

pressure:當TCP使用了超過該值的內存頁面數量時,TCP試圖穩定其內存使用,進入pressure模式,當內存消耗低於low值時則退出pressure狀態。(理想情況下這個值應該是 TCP 可以使用的總緩衝區大小的最大值 (204800 * 300 / 4096)。 )

high:允許所有tcp sockets用於排隊緩衝數據報的頁面量。(如果超過這個值,TCP 連接將被拒絕,這就是爲什麼不要令其過於保守 (512000 * 300 / 4096) 的原因了。 在這種情況下,提供的價值很大,它能處理很多連接,是所預期的 2.5 倍;或者使現有連接能夠傳輸 2.5 倍的數據。 我的網絡裏爲192000 300000 732000)

一般情況下這些值是在系統啓動時根據系統內存數量計算得到的。

net.ipv4.ip_local_port_range

32768

61000

1024

65000

表示用於向外連接的端口範圍,默認比較小,這個範圍同樣會間接用於NAT表規模。

net.ipv4.ip_conntrack_max

65535

65535

系統支持的最大ipv4連接數,默認65536(事實上這也是理論最大值),同時這個值和你的內存大小有關,如果內存128M,這個值最大8192,1G以上內存這個值都是默認65536

net.ipv4.netfilter.ip_conntrack_max

65535

65535

防火牆參數,同上
net.ipv4.netfilter.
ip_conntrack_tcp_timeout_established

432000

180

已建立的tcp連接的超時時間,默認432000,也就是5天。影響:這個值過大將導致一些可能已經不用的連接常駐於內存中,佔用大量鏈接資源,從而可能導致NAT ip_conntrack: table full的問題。建議:對於NAT負載相對本機的 NAT表大小很緊張的時候,可能需要考慮縮小這個值,以儘早清除連接,保證有可用的連接資源;如果不緊張,不必修改

 網絡內核

文件所處目錄/proc/sys/net/core/

名稱

默認值

建議值

描述

netdev_max_backlog
 

 

1024

16384

每個網絡接口接收數據包的速率比內核處理這些包的速率快時,允許送到隊列的數據包的最大數目,對重負載服務器而言,該值需要調高一點。

somaxconn 
 

 

128

16384

用來限制監聽(LISTEN)隊列最大數據包的數量,超過這個數量就會導致鏈接超時或者觸發重傳機制。

web應用中listen函數的backlog默認會給我們內核參數的net.core.somaxconn限制到128,而nginx定義的NGX_LISTEN_BACKLOG默認爲511,所以有必要調整這個值。對繁忙的服務器,增加該值有助於網絡性能

wmem_default

 

129024

129024

默認的發送窗口大小(以字節爲單位)

rmem_default

 

129024

129024

默認的接收窗口大小(以字節爲單位)

rmem_max

 

129024

873200

最大的TCP數據接收緩衝

wmem_max

129024

873200

最大的TCP數據發送緩衝

shell腳本基礎

linux中常用的通配符

  • * 匹配0或多個字符
  • ? 匹配任意1個字符
  • [list] 匹配list中的任意單一字符
  • [!list] 匹配除list中的任意單一字符以外的字符
  • [c1-c2] 匹配c1-c2中的任意單一字符,如:[0-9][a-z]
  • {strin1,string2,...} 匹配string1或string2(或更多)其1字符串
  • {c1..c2} 匹配c1-c2中全部字符串,如{1..10},如利用通配符批量創建5個文件 touch file{1..5}.txt

常用的shell命令總結

cat命令

cat(concatenate):將文件或標準輸入組合輸出到標準輸出,常用來顯示文件內容或連接文件,反向顯示文件內容命令爲tac。

  • 格式:cat [選項] [文件]
  • 可選參數:
    • -A:show all
    • -b:對非空輸出行 編號
    • -n:對所有輸出行進行行編號
    • -s:多個空白行轉換爲一個空白符
      例如將a.log文件的內容加上行號後輸入到b.log這個文件中,多個空行轉換成一個行輸出 cat -ns a.log > b.log

more命令

more:

功能類似於cat,cat將文件內容從上到下顯示,more命令一頁頁顯示,方便閱讀,按空格鍵往下翻,按b(back)鍵顯示上一頁,=鍵輸出當前行號,q鍵退出more。此外還可以搜索字符串

  • 格式:more [選項] [文件]
  • 可選參數:
    • +n:從第n行開始顯示
    • -n:定義屏幕大小爲n行
    • +/pattern:在文件顯示前搜索字符串pattern,從該字符串前兩行開始顯示
      如,從a.log文件中查找第一個出現"g"字符串的行,並從該處前兩行開始顯示輸出,規定每屏的行數爲5
      more -5 +/g a.log

例子:

aijian.shi@U-aijian-shi:~/ALM$ cat test.log                   #顯示所有日誌內容
aijian.shi@U-aijian-shi:~/ALM$ more +3 test.log               #從第三行開始顯示日誌內

less命令

less工具也是對文件或其它輸出進行分頁顯示的工具,應該說是linux正統查看文件內容的工具,功能極其強大。less 的用法比起 more 更加的有彈性。 在 more 的時候,我們並沒有辦法向前面翻, 只能往後面看,但若使用了 less 時,就可以使用 [pageup] [pagedown] 等按 鍵的功能來往前往後翻看文件,更容易用來查看一個文件的內容!除此之外,在 less 裏頭可以擁有更多的搜索功能,不止可以向下搜,也可以向上搜。

  • 格式:less [選項] [文件]
  • 可選參數:
    • -f:強迫打開
    • -i:忽略大小寫
    • -N:顯示每列行號
    • -s:顯示連續空行爲一行
    • 常用操作:
      • /字符串:向下搜索字符串
      • ?字符串:向上搜索字符串
        如,顯示文件a.log中的內容,搜索字符串"hello",可以使用如下命令 less a.log /hello

less與cat和more的區別:

  • cat命令用於顯示整個文件的內容,單獨使用沒有翻頁功能。因此經常和more命令搭配使用,cat命令還有就是可以將多個文件合併成一個文件的功能。
  • more命令功能:讓畫面在顯示滿一頁時暫停,此時可按空格鍵繼續顯示下一個頁面,或按q鍵退出顯示
  • less命令功能:less命令與more命令類似,也可以用了瀏覽超過一頁的文件。所不同的是less命令除了可以按空格鍵向下顯示文件外,還可以利用上下鍵來捲動文件。當要結束瀏覽時,只要在less命令的提示符:下按q鍵即可。其實這三個命令除了cat命令有合併文件的功能外,其餘功能上相似,只是從瀏覽習慣和顯示方式上有所不同。

head命令

:顯示文件的開頭,默認爲前10行,對應於tail命令,顯示文件末尾內容

  • 格式:head [選項] [文件]
  • 可選參數:
    • -q:隱藏文件名
    • -v:顯示文件名
    • -c <字節數>:顯示字節數
    • -n <行數>:顯示行數,參數爲負時顯示文件末尾行
      如,顯示a.log和b.log文件的前5行內容 head -n 5 a.log b.log

find命令

find:

沿文件層次結構向下遍歷,匹配符合條件的文件,並執行相應操作

  • 格式:find [搜索路徑] [表達式]
  • 默認路徑是當前目錄,默認表達式爲 -print
  • 可選參數:
    • -print:輸出到標準輸出
    • -delete:刪除搜索到的文件
    • -exec:對匹配的文件執行參數給出的shell命令
    • -name:按文件名查找文件
    • -type:按類型查找文件,常用文件類型有b(塊設備文件)、c(字符設備文件)、d(目錄)、f(普通文件)、l(符號鏈接)
    • -perm:根據文件權限查找文件
    • -user:所有者選項

舉例:

打印當前目錄下所有以.txt結尾的符號鏈接
find  . -type  l -name ".txt" -print
打印當前目錄下所有權限是777的php文件
find . -type f -name ".php" -perm 777
打印當前目錄下root用戶擁有的所有文件
find  .  -type  f -user root
打印當前目錄下權限不是777和664的所有文件
find . -type f (! -perm 777 -and ! -perm 664 )

grep命令

grep:一種強大的文本搜索工具,它能使用正則表達式搜索文本,並把匹配的行打印出來

  • 格式:grep [選項] pattern [文件]
  • 可選參數:
    • -c:計算搜索到字符串即pattern的次數
    • -i:忽略大小寫
    • -n:輸出行號
    • -v:反向選擇,打印不匹配的行
    • -r:遞歸搜索
    • -E:將範本樣式爲延伸的普通表示法來使用,意味着使用擴展正則表達式
    • -color=auto:找到的關鍵字加顏色顯示
    • -o:只打印匹配項,一個個按列顯示

舉例:

將/etc/passwd文件中出現root的行取出來,關鍵字部分加顏色顯示
grep "root" /etc/passwd --color=auto
將/etc/passwd文件中沒有出現root和nologin的行取出來
grep -v "root" /etc/passwd | grep -v "nologin"
在當前目錄下遞歸搜索文件中包含main()的文件,經常用於查找某些函數位於哪些源碼文件中
grep -r "main()"

awk命令

awk是行處理器: 相比較屏幕處理的優點,在處理龐大文件時不會出現內存溢出或是處理緩慢的問題,通常用來格式化文本信息

awk處理過程: 依次對每一行進行處理,然後輸出

awk命令形式:

awk [-F|-f|-v] ‘BEGIN{} //{command1; command2} END{}’ file

 [-F|-f|-v]   大參數,-F指定分隔符,-f調用腳本,-v定義變量 var=value

'  '          引用代碼塊

BEGIN   初始化代碼塊,在對每一行進行處理之前,初始化代碼,主要是引用全局變量,設置FS分隔符

//           匹配代碼塊,可以是字符串或正則表達式

{}           命令代碼塊,包含一條或多條命令

;          多條命令使用分號分隔

END      結尾代碼塊,在對每一行進行處理之後再執行的代碼塊,主要是進行最終計算或輸出結尾摘要信息

 

特殊要點:

$0           表示整個當前行

$1           每行第一個字段

NF          字段數量變量

NR          每行的記錄號,多文件記錄遞增

FNR        與NR類似,不過多文件記錄不遞增,每個文件都從1開始

\t            製表符

\n           換行符

FS          BEGIN時定義分隔符

RS       輸入的記錄分隔符, 默認爲換行符(即文本是按一行一行輸入)

~            匹配,與==相比不是精確比較

!~           不匹配,不精確比較

==         等於,必須全部相等,精確比較

!=           不等於,精確比較

&&      邏輯與

||             邏輯或

+            匹配時表示1個或1個以上

/[0-9][0-9]+/   兩個或兩個以上數字

/[0-9][0-9]*/    一個或一個以上數字

FILENAME 文件名

OFS       輸出字段分隔符, 默認也是空格,可以改爲製表符等

ORS         輸出的記錄分隔符,默認爲換行符,即處理結果也是一行一行輸出到屏幕

-F'[:#/]'   定義三個分隔符

 

print & $0

print 是awk打印指定內容的主要命令

awk '{print}'  /etc/passwd   ==   awk '{print $0}'  /etc/passwd  

awk '{print " "}' /etc/passwd                                           //不輸出passwd的內容,而是輸出相同個數的空行,進一步解釋了awk是一行一行處理文本

awk '{print "a"}'   /etc/passwd                                        //輸出相同個數的a行,一行只有一個a字母

awk -F":" '{print $1}'  /etc/passwd 

awk -F: '{print $1; print $2}'   /etc/passwd                   //將每一行的前二個字段,分行輸出,進一步理解一行一行處理文本

awk  -F: '{print $1,$3,$6}' OFS="\t" /etc/passwd        //輸出字段1,3,6,以製表符作爲分隔符

參考文檔: http://blog.chinaunix.net/uid-23302288-id-3785105.html

sed命令

sed屬於流編輯器,即在編輯文件的時候不用把整個文件都讀入內存,可以一行行的讀入,操作完成後再讀入下一行,可以佔用較小的內存資源。

  • 格式:sed [選項] [操作] [文件名]
    如將/etc/passwd的內容列出並且打印行號,同時,請將第2-5行刪除
    nl /etc/passwd | sed '2,5d'
  • 與grep一樣,sed也支持特殊元字符,來進行模式查找與替換。不同的是,sed使用的正則表達式是括在/之間的模式。如果要把正則表達式分隔符/改爲另一個字符,比如o,只要在這個字符前加入一個\,在字符後跟上正則表達式,再跟上這個字符即可。

top命令

第一行(總覽):

當前時間、系統啓動時間、當前系統登錄用戶數目、平均負載(1分鐘,10分鐘,15分鐘)

平均負載(load average),一般對於單個cpu來說,負載在0~1.00之間是正常的,超過1.00須引起注意。在多核cpu中,系統平均負載不應該高於cpu核心的總數。

第二行(任務數)

進程總數、運行進程數、休眠進程數、終止進程數、僵死進程數。

第三行(cpu佔比)

%us用戶空間佔用cpu百分比;
%sy內核空間佔用cpu百分比;
%ni用戶進程空間內改變過優先級的進程佔用cpu百分比;
%id空閒cpu百分比,反映一個系統cpu的閒忙程度。越大越空閒;
%wa等待輸入輸出(I/O)的cpu百分比;
%hi指的是cpu處理硬件中斷的時間;
%si值的是cpu處理軟件中斷的時間;

%st用於有虛擬cpu的情況,用來指示被虛擬機偷掉的cpu時間。

第四行(內存佔用量)

  • total總的物理內存;
  • used使用物理內存大小;
  • free空閒物理內存;
  • buffers用於內核緩存的內存大小

第五行(交換空間佔用量)

  • total總的交換空間大小;
  • used已經使用交換空間大小;
  • free空間交換空間大小;
  • cached緩衝的交換空間大小

cache和buffer的區別:

  • Cache:緩存區,是高速緩存,是位於CPU和主內存之間的容量較小但速度很快的存儲器,因爲CPU的速度遠遠高於主內存的速度,CPU從內存中讀取數據需等待很長的時間,而  Cache保存着CPU剛用過的數據或循環使用的部分數據,這時從Cache中讀取數據會更快,減少了CPU等待的時間,提高了系統的性能。
  • Cache並不是緩存文件的,而是緩存塊的(塊是I/O讀寫最小的單元);Cache一般會用在I/O請求上,如果多個進程要訪問某個文件,可以把此文件讀入Cache中,這樣下一個進程獲取CPU控制權並訪問此文件直接從Cache讀取,提高系統性能
  • Buffer:緩衝區,用於存儲速度不同步的設備或優先級不同的設備之間傳輸數據;通過buffer可以減少進程間通信需要等待的時間,當存儲速度快的設備與存儲速度慢的設備進行通信時,存儲慢的數據先把數據存放到buffer,達到一定程度存儲快的設備再讀取buffer的數據,在此期間存儲快的設備CPU可以幹其他的事情。

第六行(進程佔用詳情):

  • PID:進程號
  • USER:運行用戶
  • PR:優先級,PR(Priority)所代表的值有什麼含義?它其實就是進程調度器分配給進程的時間片長度,單位是時鐘個數,那麼一個時鐘需要多長時間呢?這跟CPU的主頻以及操作系統平臺有關,比如linux上一般爲10ms,那麼PR值爲15則表示這個進程的時間片爲150ms。
  • NI: 任務nice值
  • VIRT: 進程使用的虛擬內存總量,單位kb。VIRT=SWAP+RES
  • RES: 物理內存用量
  • SHR: 共享內存用量
  • S: 該進程的狀態。其中S代表休眠狀態;D代表不可中斷的休眠狀態;R代表運行狀態;Z代表僵死狀態;T代表停止或跟蹤狀態
  • %CPU: 該進程自最近一次刷新以來所佔用的CPU時間和總時間的百分比
  • %MEM: 該進程佔用的物理內存佔總內存的百分比
  • TIME+:累計cpu佔用時間
  • COMMAND:該進程的命令名稱,如果一行顯示不下,則會進行截取。內存中的進程會有一個完整的命令行

ps命令

使用該命令可以確定有哪些進程正在運行和運行的狀態、進程是否結束、進程有沒有殭屍、哪些進程佔用了過多的資源等等.總之大部分信息都是可以通過執行該命令得到。ps是顯示瞬間進程的狀態,並不動態連續;如果想對進程進行實時監控應該用top命令。

參數:

  • -A :所有的進程均顯示出來,與 -e 具有同樣的效用;
  • -a : 顯示現行終端機下的所有進程,包括其他用戶的進程;
  • -u :以用戶爲主的進程狀態 ;
  • x :通常與 a 這個參數一起使用,可列出較完整信息。

輸出格式規劃:

  • l :較長、較詳細的將該PID 的的信息列出;
  • j :工作的格式 (jobs format)
  • -f :做一個更爲完整的輸出。

舉例,將目前屬於您自己這次登入的 PID 與相關信息列示出來:

[work@sandbox_java05 ~]$ ps -l
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S   500 22665 22664  0  80   0 - 28661 wait   pts/2    00:00:00 bash
0 R   500 22693 22665  0  80   0 - 28501 -      pts/2    00:00:00 ps

各相關信息的意義爲:

  • F 代表這個程序的旗標 (flag), 4 代表使用者爲 superuser;
  • S 代表這個程序的狀態 (STAT);
  • UID 代表執行者身份
  • PID 進程的ID號!
  • PPID 父進程的ID;
  • C CPU使用的資源百分比
  • PRI指進程的執行優先權(Priority的簡寫),其值越小越早被執行;
  • NI 這個進程的nice值,其表示進程可被執行的優先級的修正數值。
  • ADDR 這個是內核函數,指出該程序在內存的那個部分。如果是個執行 的程序,一般就是『 - 』
  • SZ 使用掉的內存大小;
  • WCHAN 目前這個程序是否正在運作當中,若爲 - 表示正在運作;
  • TTY 登入者的終端機位置;
  • TIME 使用掉的 CPU 時間。
  • CMD 所下達的指令名稱

 列出目前所有的正在內存當中的程序:

  • USER:該進程屬於那個使用者賬號。
  • PID :該進程的進程ID號。
  • %CPU:該進程使用掉的 CPU 資源百分比;
  • %MEM:該進程所佔用的物理內存百分比;
  • VSZ :該進程使用掉的虛擬內存量 (Kbytes)
  • RSS :該進程佔用的固定的內存量 (Kbytes)
  • TTY :該進程是在那個終端機上面運作,若與終端機無關,則顯示 ?。另外, tty1-tty6 是本機上面的登入者程序,若爲 pts/0 等等的,則表示爲由網絡連接進主機的程序。
  • STAT:該程序目前的狀態,主要的狀態有:
  • R :該程序目前正在運作,或者是可被運作;
  • S :該程序目前正在睡眠當中,但可被某些訊號(signal) 喚醒。
  • T :該程序目前正在偵測或者是停止了;
  • Z :該程序應該已經終止,但是其父程序卻無法正常的終止他,造成 zombie (疆屍) 程序的狀態
  • START:該進程被觸發啓動的時間;
  • TIME :該進程實際使用 CPU 運作的時間。
  •  COMMAND:該程序的實際指令。

vim命令

 1.刪除字符
  要刪除一個字符,只需要將光標移到該字符上按下"x"。

2.刪除一行
  刪除一整行內容使用"dd"命令。刪除後下面的行會移上來填補空缺。

3.刪除換行符
  在Vim中你可以把兩行合併爲一行,也就是說兩行之間的換行符被刪除了:命令是"J"。

4.撤銷
  如果你誤刪了過多的內容。顯然你可以再輸入一遍,但是命令"u" 更簡便,它可以撤消上一次的操作。

5.重做
  如果你撤消了多次,你還可以用CTRL-R(重做)來反轉撤消的動作。換
句話說,它是對撤消的撤消。撤消命令還有另一種形式,"U"命令,它一次撤消對一行的全部操作。第二次使用該命令則會撤消前一個"U"的操作。
  注:用"u"和CTRL-R你可以找回任何一個操作狀態。

6.追加
  "i"命令可以在當前光標之前插入文本。
  "a"命令可以在當前光標之後插入文本。
  "o"命令可以在當前行的下面另起一行,並使當前模式轉爲Insert模式。
  "O"命令(注意是大寫的字母O)將在當前行的上面另起一行。

7.使用命令計數
  假設你要向上移動9行。這可以用"kkkkkkkkk"或"9k"來完成。事實上,很多命令都可以接受一個數字作爲重複執行同一命令的次數。比如剛纔的例子,要在行尾追加三個感嘆號,當時用的命令是"a!!!"。另一個辦法是用"3a!"命令。3說明該命令將被重複執行3次。同樣,刪除3個字符可以用"3x"。指定的數字要緊挨在它所要修飾的命令前面。

8.退出
  要退出Vim,用命令"ZZ"。該命令保存當前文件並退出Vim。

9.放棄編輯
  丟棄所有的修改並退出,用命令":q!"。用":e!"命令放棄所有修改並重新載入該文件的原始內容。

10.以Word爲單位的移動
  使用"w"命令可以將光標向前移動一個word的首字符上;比如"3w"將光標向前移動3個words。"b"命令則將光標向後移動到前一個word的首字符上。
  "e"命令會將光標移動到下一個word的最後一個字符。命令"ge",它將光標移動到前一個word的最後一個字符上。、

11.移動到行首或行尾
  "$"命令將光標移動到當前行行尾。如果你的鍵盤上有一個鍵,它的作用也一樣。"^"命令將光標移動到當前行的第一個非空白字符上。"0"命令則總是把光標移動到當前行的第一個字符上。鍵也是如此。"$"命令還可接受一個計數,如"1$"會將光標移動到當前行行尾,"2$"則會移動到下一行的行尾,如此類推。"0"命令卻不能接受類似這樣的計數,命令"^"前加上一個計數也沒有任何效果。

12.移動到指定字符上
  命令"fx"在當前行上查找下一個字符x(向右方向),可以帶一個命令計數"F"命令向左方向搜索。"tx"命令形同"fx"命令,只不過它不是把光標停留在被搜索字符上,而是在它之前的一個字符上。提示:"t"意爲"To"。該命令的反方向版是"Tx"。這4個命令都可以用";"來重複。以","也是重複同樣的命令,但是方向與
原命令的方向相反。

13.以匹配一個括號爲目的移動
  用命令"%"跳轉到與當前光標下的括號相匹配的那一個括號上去。如果當前光標在"("上,它就向前跳轉到與它匹配的")"上,如果當前在")"上,它就向後自動跳轉到匹配的"("上去.

14.移動到指定行
  用"G"命令指定一個命令計數,這個命令就會把光標定位到由命令計數指定的行上。比如"33G"就會把光標置於第33行上。沒有指定命令計數作爲參數的話, "G"會把光標定位到最後一行上。"gg"命令是跳轉到第一行的快捷的方法。
  另一個移動到某行的方法是在命令"%"之前指定一個命令計數比如"50%"將會把光標定位在文件的中間. "90%"跳到接近文件尾的地方。
  命令"H","M","L",分別將光標跳轉到第一行,中間行,結尾行部分。

15.告訴你當前的位置
  使用CTRL-G命令。"set number"在每行的前面顯示一個行號。相反關閉行號用命令":set nonumber"。":set ruler"在Vim窗口的右下角顯示當前光標位置。

16.滾屏
  CTRL-U顯示文本的窗口向上滾動了半屏。CTRL-D命令將窗口向下移動半屏。一次滾動一行可以使用CTRL-E(向上滾動)和CTRL-Y(向下滾動)。要向前滾動一整屏使用命令CTRL-F。另外CTRL-B是它的反向版。"zz"命令會把當前行置爲屏幕正中央,"zt"命令會把當前行置於屏幕頂端,"zb"則把當前行置於屏幕底端.

17.簡單搜索
  "/string"命令可用於搜索一個字符串。要查找上次查找的字符串的下一個位置,使用"n"命令。如果你知道你要找的確切位置是目標字符串的第幾次出現,還可以在"n"之前放置一個命令計數。"3n"會去查找目標字符串的第3次出現。
  "?"命令與"/"的工作相同,只是搜索方向相反."N"命令會重複前一次查找,但是與最初用"/"或"?"指定的搜索方向相反。
  如果查找內容忽略大小寫,則用命令"set ignorecase", 返回精確匹配用命令"set noignorecase" 。

18.在文本中查找下一個word
  把光標定位於這個word上然後按下"*"鍵。Vim將會取當前光標所在的word並將它作用目標字符串進行搜索。"#"命令是"*"的反向版。還可以在這兩個命令前加一個命令計數:"3*"查找當前光標下的word的第三次出現。

19.查找整個word
  如果你用"/the"來查找Vim也會匹配到"there"。要查找作爲獨立單詞的"the"使用如下命令:"/the\>"。"\>"是一個特殊的記法,它只匹配一個word的結束處。近似地,"\<"匹配到一個word的開始處。這樣查找作爲一個word的"the"就可以用:"/\"。

20.高亮顯示搜索結果
  開啓這一功能用":set hlsearch",關閉這一功能:":set nohlsearch"。如果只是想去掉當前的高亮顯示,可以使用下面的命令:":nohlsearch"(可以簡寫爲noh)。

21.匹配一行的開頭與結尾
   ^ 字符匹配一行的開頭。$字符匹配一行的末尾。
   所以"/was$"只匹配位於一行末尾的單詞was,所以"/^was"只匹配位於一行開始的單詞was。

22.匹配任何的單字符
  .這個字符可以匹配到任何字符。比如"c.m"可以匹配任何前一個字符是c,後一個字符是m的情況,不管中間的字符是什麼。

23.匹配特殊字符
  放一個反斜槓在特殊字符前面。如果你查找"ter。",用命令"/ter\。"

24.使用標記
  當你用"G"命令從一個地方跳轉到另一個地方時,Vim會記得你起跳的位置。這個位置在Vim中是一個標記。使用命令" `` "可以使你跳回到剛纔的出發點。
  ``命令可以在兩點之間來回跳轉。CTRL-O命令是跳轉到你更早些時間停置光標的位置(提示:O意爲older). CTRL-I則是跳回到後來停置光標的更新的位置(提示:I在鍵盤上位於O前面)。
    注:使用CTRL-I 與按下鍵一樣。

25.具名標記
   命令"ma"將當前光標下的位置名之爲標記"a"。從a到z一共可以使用26個自定義的標記。要跳轉到一個你定義過的標記,使用命令" `marks "marks就是定義的標記的名字。命令" 'a "使你跳轉到a所在行的行首," `a "會精確定位a所在的位置。命令:":marks"用來查看標記的列表。
  命令delm!刪除所有標記。

26.操作符命令和位移
  "dw"命令可以刪除一個word,"d4w"命令是刪除4個word,依此類推。類似有"d2e"、"d$"。此類命令有一個固定的模式:操作符命令+位移命令。首先鍵入一個操作符命令。比如"d"是一個刪除操作符。接下來是一個位移命。比如"w"。這樣任何移動光標命令所及之處,都是命令的作用範圍。

27.改變文本
  操作符命令是"c",改變命令。它的行爲與"d"命令類似,不過在命令執行後會進入Insert模式。比如"cw"改變一個word。或者,更準確地說,它刪除一個word並讓你置身於Insert模式。
  "cc"命令可以改變整行。不過仍保持原來的縮進。
  "c$"改變當前光標到行尾的內容。
  快捷命令:x 代表dl(刪除當前光標下的字符)
            X 代表dh(刪除當前光標左邊的字符)
            D 代表d$(刪除到行尾的內容)
            C 代表c$(修改到行尾的內容)
            s 代表cl(修改一個字符)
            S 代表cc(修改一整行)
  命令"3dw"和"d3w"都是刪除3個word。第一個命令"3dw"可以看作是刪除一個word的操作執行3次;第二個命令"d3w"是一次刪除3個word。這是其中不明顯的差異。事實上你可以在兩處都放上命令記數,比如,"3d2w"是刪除兩個word,重複執行3次,總共是6個word。

28.替換單個字符
  "r"命令不是一個操作符命令。它等待你鍵入下一個字符用以替換當前光標下的那個字符。"r"命令前輟以一個命令記數是將多個字符都替換爲即將輸入的那個字符。要把一個字符替換爲一個換行符使用"r"。它會刪除一個字符並插入一個換行符。在此處使用命令記數只會刪除指定個數的字符:"4r"將把4個字符替換爲一個換行符。

29.重複改動
  "."命令會重複上一次做出的改動。"."命令會重複你做出的所有修改,除了"u"命令CTRL-R和以冒號開頭的命令。"."需要在Normal模式下執行,它重複的是命令,而不是被改動的內容,

30.Visual模式
  按"v"可以進入Visual模式。移動光標以覆蓋你想操縱的文本範圍。同時被選中的文本會以高亮顯示。最後鍵入操作符命令。

31.移動文本
  以"d"或"x"這樣的命令刪除文本時,被刪除的內容還是被保存了起來。你還可以用p命令把它取回來。"P"命令是把被去回的內容放在光標之前,"p"則是放在光標之後。對於以"dd"刪除的整行內容,"P"會把它置於當前行的上一行。"p"則是至於當前行的後一行。也可以對命令"p"和"P"命令使用命令記數。它的效果是同樣的內容被取回指定的次數。這樣一來"dd"之後的"3p"就可以把被刪除行的3 份副本放到當前位置。
  命令"xp"將光標所在的字符與後一個字符交換。

32.複製文本
  "y"操作符命令會把文本複製到一個寄存器3中。然後可以用"p"命令把它取回。因爲"y"是一個操作符命令,所以你可以用"yw"來複制一個word. 同樣可以使用命令記數。如下例中用"y2w"命令複製兩個word,"yy"命令複製一整行,"Y"也是複製整行的內容,複製當前光標至行尾的命令是"y$"。

33.文本對象
  "diw" 刪除當前光標所在的word(不包括空白字符) "daw" 刪除當前光標所在的word(包括空白字符)

34.快捷命令
  x 刪除當前光標下的字符("dl"的快捷命令)
  X 刪除當前光標之前的字符("dh"的快捷命令)
  D 刪除自當前光標至行尾的內容("d$"的快捷命令)
  dw 刪除自當前光標至下一個word的開頭
  db 刪除自當前光標至前一個word的開始
  diw 刪除當前光標所在的word(不包括空白字符)
  daw 刪除當前光標所在的word(包括空白字符)
  dG 刪除當前行至文件尾的內容
  dgg 刪除當前行至文件頭的內容
  如果你用"c"命令代替"d"這些命令就都變成更改命令。使用"y"就是yank命令,如此類推。

35.編輯另一個文件
  用命令":edit foo.txt",也可簡寫爲":e foo.txt"。

36.文件列表
  可以在啓動Vim時就指定要編輯多個文件,用命令"vim one.c two.c three.c"。Vim將在啓動後只顯示第一個文件,完成該文件的編輯後,可以用令:":next"或":n"要保存工作成果並繼續下一個文件的編輯,命令:":wnext"或":wn"可以合併這一過程。

37.顯示當前正在編輯的文件
  用命令":args"。

38.移動到另一個文件
  用命令":previous" ":prev"回到上一個文件,合併保存步驟則是":wprevious" ":wprev"。要移到最後一個文件":last",到第一個":first".不過沒有":wlast"或者":wfirst"這樣的命令。可以在":next"和":previous"命令前面使用一個命令計數。

39.編輯另一個文件列表
  不用重新啓動Vim,就可以重新定義一個文件列表。命令":args five.c six.c seven.h"定義了要編輯的三個文件。

39.自動存盤
  命令":set autowrite","set aw"。自動把內容寫回文件: 如果文件被修改過,在每個:next、:rewind、:last、:first、:previous、:stop、:suspend、:tag、:!、:make、CTRL-] 和 CTRL-^命令時進行。
  命令":set autowriteall","set awa"。和 'autowrite' 類似,但也適用於":edit"、":enew"、":quit"、":qall"、":exit"、":xit"、":recover" 和關閉 Vim 窗口。置位本選項也意味着Vim 的行爲就像打開 'autowrite' 一樣。

40.切換到另一文件
  要在兩個文件間快速切換,使用CTRL-^。

41.文件標記
  以大寫字母命名的標記。它們是全局標記,它們可以用在任何文件中。比如,正在編輯"fab1.java",用命令"50%mF"在文件的中間設置一個名爲F的標記。然後在"fab2.java"文件中,用命令"GnB"在最後一行設置名爲B的標記。在可以用"F"命令跳轉到文件"fab1.java"的半中間。或者編輯另一個文件,"'B"命令會再把你帶回文件"fab2.java"的最後一行。
  要知道某個標記所代表的位置是什麼,可以將該標記的名字作爲"marks"命令的參數":marks M"或者連續跟上幾個參數":marks MJK"
  可以用CTRL-O和CTRL-I可以跳轉到較早的位置和靠後的某位置。

42.查看文件
  僅是查看文件,不向文件寫入內容,可以用只讀形式編輯文件。用命令:
vim -R file。如果是想強制性地避免對文件進行修改,可以用命令:
vim -M file。

43.更改文件名
  將現有文件存成新的文件,用命令":sav(eas) move.c"。如果想改變當前正在編輯的文件名,但不想保存該文件,就可以用命令:":f(ile) move.c"。

44.分割一個窗口
  打開一個新窗口最簡單的辦法就是使用命令:":split"。CTRL-W 命令可以切換當前活動窗口。

45.關閉窗口
  用命令:"close".可以關閉當前窗口。實際上,任何退出文件編輯的命令":quit"和"ZZ"都會關閉窗口,但是用":close" 可以阻止你關閉最後一個Vim,以免以意外地整個關閉了Vim。

46.關閉除當前窗口外的所有其他窗口
  用命令:":only",關閉除當前窗口外的所有其它窗口。如果這些窗口中有被修改過的,你會得到一個錯誤信息,同時那個窗口會被留下來。

47.爲另一個文件分隔出一個窗口
  命令":split two.c"可以打開第二個窗口同時在新打開的窗口中開始編輯作爲
參數的文件。如果要打開一個新窗口並開始編輯一個空的緩衝區,使用命令:":new"。

48.垂直分割
  用命令":vsplit或::vsplit two.c"。同樣有一個對應的":vnew"命令,用於垂直分隔窗口並在其中打開一個新的空緩衝區。

49.切換窗口
  CTRL-W h 到左邊的窗口
  CTRL-W j 到下面的窗口
  CTRL-W k 到上面的窗口
  CTRL-W l 到右邊的窗口
  CTRL-W t 到頂部窗口
  CTRL-W b 到底部窗口

50.針對所有窗口操作的命令
  ":qall"放棄所有操作並退出,":wall"保存所有,":wqall"保存所有並退出。

51.爲每一個文件打開一個窗口
  使用"-o"選項可以讓Vim爲每一個文件打開一個窗口:
"vim -o one.txt two.txt three.txt"。

52.使用vimdiff查看不同
  "vimdiff main.c~ main.c",另一種進入diff模式的辦法可以在Vim運行中操作。編輯文件"main.c",然後打開另一個分隔窗口顯示其不同:
  ":edit main.c"
  ":vertical diffpatch main.c.diff"。
53.頁籤
   命令":tabe(dit) thatfile"在一個窗口中打開"thatfile",該窗口占據着整個的Vim顯示區域。命令":tab split/new"結果是新建了一個擁有一個窗口的頁籤。以用"gt"命令在不同的頁籤間切換。

shell編程

寫不動了,以後總結。參考文檔:

https://www.jianshu.com/p/e1c8e5bfa45e

https://blog.csdn.net/ithomer/article/details/6038121

參考文檔:

https://www.cnblogs.com/olinux/p/5577767.html

https://blog.csdn.net/fgf00/article/details/77544325

https://blog.51cto.com/yangrong/1321594

https://www.jianshu.com/p/d3690a783bd2

https://www.jianshu.com/p/41dc33b97419

https://blog.csdn.net/baiye_xing/article/details/74331041

https://blog.csdn.net/ezbuy/article/details/80446586

https://fableking.iteye.com/blog/1141518

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章