日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

【Linux进程、线程、任务调度】一 Linux进程生命周期 僵尸进程的含义 停止状态与作业控制 内存泄漏的真实含义 task_struct以及task_struct之间的关系

發布時間:2023/12/10 linux 34 豆豆
  • 學習交流加(可免費幫忙下載CSDN資源):
  • 個人微信: liu1126137994
  • 學習交流資源分享qq群1(已滿): 962535112
  • 學習交流資源分享qq群2: 780902027

文章目錄

    • 1、進程控制塊PCB
    • 2、進程的生命周期
    • 3、作業控制(cpulimit)
    • 4、內存泄漏到底是什么
    • 5、初見fork
    • 6、總結

本篇文章主要記錄以下學習內容:

  • Linux進程生命周期(就緒、運行、睡眠、停止、僵尸)
  • 僵尸的含義
  • 停止狀態與作業控制, cpulimit
  • 內存泄漏的真實含義
  • task_struct以及task_struct之間的關系
  • 初見fork和僵尸

1、進程控制塊PCB

Task_struct (PCB) 通俗一點的說就是描述進程資源的結構體,也可以稱為進程描述符。在這個結構體中存放著這個進程所需要的所有資源的結構的描述。例如我們能想到的進程肯定有進程id,進程的內存管理,對文件的管理,對信號的管理等,那么PCB中就肯定存有類似于下面的結構:

其中PID的數量是有限的,在我自己的Linux系統中是32768

$ cat /proc/sys/kernel/pid_max 32768 所以我們不能無限制的創建進程。

那么在Linux中Task_struct是如何被管理的呢?

  • 形成鏈表
  • 形成樹
    因為鏈表遍歷的開銷比較大,所以會在鏈表的基礎上,形成樹結構,這樣會使對進程描述符的遍歷的時間復雜度更低

  • 形成哈希 :pid->task_struct
    為了更加快捷的訪問到進程描述符,可以讓進程的pid作為索引,形成哈希結構,這樣在實現進程的調度算法時,效率會更高效。

  • 2、進程的生命周期

    上圖表示了進程的六種狀態,就緒態,運行態,深度睡眠態,淺睡眠態,停止態,僵尸態。

    就緒態和運行態在數值上是相等的,都是由宏TASK_RUNNING定義。就緒態和運行太可以相互轉換,運行態可以到停止態(例如ctrl+z),停止態可以恢復到就緒態。

    其中,就緒態,運行態,停止態很好理解,這里不再贅述。

    • 深睡眠
      進程處于睡眠態(調用sleep),等到資源到位,就可以被調度(變成就緒態TASK_RUNNING)。
    • 淺睡眠
      進程處于睡眠態(調用sleep),等到資源到位,或者收到信號,就可以被調度(變成就緒態TASK_RUNNING)。

    正常的進程睡眠都是淺睡眠,但是內核中有一些進程處于睡眠態不希望被信號打斷,那么它就會處于深睡眠狀態。

    • 僵尸態
      資源已經釋放,沒有內存泄漏等!!!
      但是 Task_struct還在,這樣的話,父進程可以根據子進程的Task_struct結構體存的退出碼,查出子進程的死因。

    有內核代碼如下:

    3、作業控制(cpulimit)

    有時候我們的進程的CPU占用率非常高,為了使其他進程可以獲得CPU時間,我們可以使用一些手段降低進程的CPU占用率。

    其中cpulimit是之前比較常用的一個命令,它利用間斷性的使進程處于停止態,從而降低進程的CPU占有率。

    假設我的進程是一個死循環,且CPU占有率很高,則通過以下命令可以降低該使進程號為10111的進程的CPU占有率變為20%。

    $ cpulimit -l 20 -p 10111

    cpulimit的原理:

    4、內存泄漏到底是什么

    • 內存泄漏不是進程死了內存沒釋放

    如果進程死了(退出或者變成僵尸),它所占有的內存資源會瞬間全部釋放。

    • 內存泄漏是進程活著,但隨著時間的推移,內存消耗越來越多

    5、初見fork

    1. 初識fork

    看下面程序打印幾個hello?

    int main() {fork();printf("hello\n");fork();printf("hello\n");while (1);return 0; }

    假設p1是main函數這個進程,進入函數后,fork產生一個子進程p2,p1和p2各打印一個hello,接著p1和p2又各fork(),分別又產生兩個hello,所以一共打印6個hello。

    運行下面程序看如何打印:

    #include <stdio.h> #include <sys/wait.h> #include <stdlib.h> #include <unistd.h>int main(){pid_t pid;pid = fork();if(pid==-1){ /* 創建不成功 */perror("Can't creat new process");exit(1);}else if(pid==0){ /* pid==0,子進程運行代碼 */printf("a\n");}else { /* 父進程運行代碼 */printf("b\n");}/* 父子進程都運行的代碼 */printf("c\n");while(1); }

    運行結果為:

    • 結果分析:

    fork()函數的返回值是返回兩次的,在父進程中返回子進程的pid,在子進程中返回0。借此我們可以在代碼中區分開父子進程運行的代碼。

    進入函數后首先fork(),產生一個子進程,在子進程的進程空間的環境創建好之前,父進程就已經運行完并打印了b和c,然后子進程打印a和c。

    2. 子死父清場(life_period.c)

    #include <stdio.h> #include <sys/wait.h> #include <stdlib.h> #include <unistd.h>int main(void) {pid_t pid,wait_pid;int status;pid = fork();if (pid==-1) {perror("Cannot create new process");exit(1);} else if (pid==0) {printf("child process id: %ld\n", (long) getpid());pause();_exit(0);} else { #if 1 /* define 1 to make child process always a zomie */printf("ppid:%d\n", getpid());while(1); #endifdo {wait_pid=waitpid(pid, &status, WUNTRACED | WCONTINUED);if (wait_pid == -1) {perror("cannot using waitpid function");exit(1);}if (WIFEXITED(status))printf("child process exites, status=%d\n", WEXITSTATUS(status));if(WIFSIGNALED(status))printf("child process is killed by signal %d\n", WTERMSIG(status));if (WIFSTOPPED(status))printf("child process is stopped by signal %d\n", WSTOPSIG(status));if (WIFCONTINUED(status))printf("child process resume running....\n");} while (!WIFEXITED(status) && !WIFSIGNALED(status));exit(0);} }
    • 在if 1不改為if 0的情況下

    編譯運行程序,殺死子進程,查看父進程的僵尸態

    編譯運行:

    $ gcc life_period.c $ ./a.out Child process id:6426

    另開一個終端先看父子進程的狀態:

    然后殺死子進程:

    $ kill -9 6426

    再查看狀態:

    可以看到,子進程(pid=6426)的狀態已經變味僵尸態

    • 在if 1改為if 0的情況下

    編譯運行程序,殺死子進程,查看父進程的僵尸態

    編譯運行:

    $ gcc life_period.c $ ./a.out Child process id:6430

    另開一個終端先看父子進程的狀態:

    然后殺死子進程

    $ kill -9 6430

    在第一個終端可以看到子進程被殺死的原因

    然后父進程也退出。

    可以看出父進程可以通過waitpid()函數回收子進程的task_struct結構。

    6、總結

    • 理解Linux進程的生命周期(六種狀態)
    • 理解task_struct結構
    • 理解僵尸進程(資源已經釋放,Task_struct結構還在)
    • 理解內存泄漏的真實含義
    • 理解fork與僵尸態
    • 動手寫上述實驗代碼并自己編譯運行

    學習探討加:
    個人微信:liu1126137994
    個人qq :1126137994

    總結

    以上是生活随笔為你收集整理的【Linux进程、线程、任务调度】一 Linux进程生命周期 僵尸进程的含义 停止状态与作业控制 内存泄漏的真实含义 task_struct以及task_struct之间的关系的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。