中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

進程棧、線程棧、內核棧分別是什么

發布時間:2021-06-29 09:59:04 來源:億速云 閱讀:498 作者:chen 欄目:大數據

本篇內容主要講解“進程棧、線程棧、內核棧分別是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“進程棧、線程棧、內核棧分別是什么”吧!

進程描述符 task_struct

線程創建的時候,加上了 CLONE_VM 標記,這樣 線程的內存描述符 將直接指向 父進程的內存描述符。

內存描述符mm_struct

進程棧、線程棧、內核棧分別是什么

進程棧:stack

線程棧:使用mmap系統調用分配的空間,但是mmap分配的系統空間是什么呢?也就是上圖中的mmap區域或者說共享的內存映射區域是什么呢?它的方向是向上生長還是向下生長的?

mmap其實和堆一樣,實際上可以說他們都是動態內存分配,但是嚴格來說mmap區域并不屬于堆區,反而和堆區會爭用虛擬地址空間。

這里要提到一個很重要的概念,內存的延遲分配,只有在真正訪問一個地址的時候才建立這個地址的物理映射,這是Linux內存管理的基本思想。Linux內核在用戶申請內存的時候,只是給它分配了一個線性區(也就是虛擬內存),并沒有分配實際物理內存;只有當用戶使用這塊內存的時候,內核才會分配具體的物理頁面給用戶,這時候才占用寶貴的物理內存。內核釋放物理頁面是通過釋放先行區,找到其對應的物理頁面,將其全部釋放的過程。

進程棧、線程棧、內核棧分別是什么

struct mm_struct {
    struct vm_area_struct *mmap;           /* 內存區域鏈表 */
    struct rb_root mm_rb;                  /* VMA 形成的紅黑樹 */
    ...
    struct list_head mmlist;               /* 所有 mm_struct 形成的鏈表 */
    ...
    unsigned long total_vm;                /* 全部頁面數目 */
    unsigned long locked_vm;               /* 上鎖的頁面數據 */
    unsigned long pinned_vm;               /* Refcount permanently increased */
    unsigned long shared_vm;               /* 共享頁面數目 Shared pages (files) */
    unsigned long exec_vm;                 /* 可執行頁面數目 VM_EXEC & ~VM_WRITE */
    unsigned long stack_vm;                /* 棧區頁面數目 VM_GROWSUP/DOWN */
    unsigned long def_flags;
    unsigned long start_code, end_code, start_data, end_data;    /* 代碼段、數據段 起始地址和結束地址 */
    unsigned long start_brk, brk, start_stack;                   /* 棧區 的起始地址,堆區 起始地址和結束地址 */
    unsigned long arg_start, arg_end, env_start, env_end;        /* 命令行參數 和 環境變量的 起始地址和結束地址 */
    ...
    /* Architecture-specific MM context */
    mm_context_t context;                  /* 體系結構特殊數據 */

    /* Must use atomic bitops to access the bits */
    unsigned long flags;                   /* 狀態標志位 */
    ...
    /* Coredumping and NUMA and HugePage 相關結構體 */
};

為什么需要區分這些棧,其實都是設計上的問題。這里就我看到過的一些觀點進行匯總,供大家討論:

  1. 為什么需要單獨的進程內核棧?

    • 所有進程運行的時候,都可能通過系統調用陷入內核態繼續執行。假設第一個進程 A 陷入內核態執行的時候,需要等待讀取網卡的數據,主動調用 schedule() 讓出 CPU;此時調度器喚醒了另一個進程 B,碰巧進程 B 也需要系統調用進入內核態。那問題就來了,如果內核棧只有一個,那進程 B 進入內核態的時候產生的壓棧操作,必然會破壞掉進程 A 已有的內核棧數據;一但進程 A 的內核棧數據被破壞,很可能導致進程 A 的內核態無法正確返回到對應的用戶態了;

  2. 為什么需要單獨的線程棧?

    • 此時 A1 的棧指針 esp 如果為初始值 0x7ffc80000000,則線程 A1 一但出現函數調用,必然會破壞父進程 A 已入棧的數據。

    • 如果此時線程 A1 的棧指針和父進程最后更新的值一致,esp 為 0x7ffc8000FF00,那線程 A1 進行一些函數調用后,棧指針 esp 增加到 0x7ffc8000FFFF,然后線程 A1 休眠;調度器再次換成父進程 A 執行,那這個時候父進程的棧指針是應該為 0x7ffc8000FF00 還是 0x7ffc8000FFFF 呢?無論棧指針被設置到哪個值,都會有問題不是嗎?

    • Linux 調度程序中并沒有區分線程和進程,當調度程序需要喚醒”進程”的時候,必然需要恢復進程的上下文環境,也就是進程棧;但是線程和父進程完全共享一份地址空間,如果棧也用同一個那就會遇到以下問題。假如進程的棧指針初始值為 0x7ffc80000000;父進程 A 先執行,調用了一些函數后棧指針 esp 為 0x7ffc8000FF00,此時父進程主動休眠了;接著調度器喚醒子線程 A1: 

  3. 進程和線程是否共享一個內核棧?

    • No,線程和進程創建的時候都調用 dup_task_struct 來創建 task 相關結構體,而內核棧也是在此函數中 alloc_thread_info_node 出來的。因此雖然線程和進程共享一個地址空間 mm_struct,但是并不共享一個內核棧。

  4. 為什么需要單獨中斷棧?

    • 這個問題其實不對,ARM 架構就沒有獨立的中斷棧。

進程空間中堆和棧的區別:

空間大小:棧系統指定大小限制在8M(M 級別),棧是連續空間;堆沒有限定,是不連續存儲空間,靠鏈表鏈接。

分配方式:堆都是程序員代碼中動態分配和回收的,沒有回收會產生內存泄露;棧有2種分配方式:靜態分配和動態分配。靜態分配是編譯器完成的,比如局部變量的分配。動態分配由alloca函數進行分配,但是棧的動態分配和堆是不同的,他的動態分配是由編譯器進行釋放,無需我們手工實現。

分配效率:棧分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執行;堆是通過調用庫函數

棧:在函數調用時,第一個進棧的是主函數中后的下一條指令(函數調用語句的下一條可執行語句)的地址,然后是函數的各個參數,在大多數的 C 編譯器中,參數是由右往左入棧的,然后是函數中的局部變量。注意靜態變量是不入棧的。
當本次函數調用結束后,局部變量先出棧,然后是參數,最后棧頂指針指向最開始存的地址,也就是主函數中的下一條指令,程序由該點繼續運行。
堆:一般是在堆的頭部用一個字節存放堆的大小。堆中的具體內容有程序員安排。

總之,棧比堆效率高,但沒有堆靈活,優先使用棧,大內存使用堆。

char a[] = "hello"; //字符數組a的容量是6個字符,其內容為hello。a的內容可以改變,如a[0]= ‘X’

char *p = "world";//指針p指向常量字符串“world”(位于靜態存儲區,內容為world),常量字符串的內容是不可以被修改的。

/**
*內核空間
*棧:grow down,大小系統設置~8M,連續空間,編譯器自動分配
*Memory Mapping Seg:堆棧共享,線程棧
*堆:grow up,大小硬件定,不連續空間,程序員malloc
*BSS:Block Started by Symbol,未初始化的全局變量和靜態變量(靜態data區)
*數據段:存放已初始化的全局變量、靜態變量(全局和局部)、const常量數據(常量data區)
*代碼段:存放CPU執行的機器指令,代碼區是可共享,并且是只讀的。這部分區域的大小在程序運行前就已經確定
**/

#include <string>
int a=0;    //數據段:全局初始化變量
char *p1;   //BSS:全局未初始化變量
void main()
{
    int b;//棧
    char s[] = "abc";   //棧
    char *p2;         //棧
    char *p3="123456";   //123456\0在常量區(代碼段??),p3在棧上。
    static int c=0;   //數據段:全局(靜態)初始化區
    *p1 = (char*)malloc(10);  //分配得來的10字節區域在堆上
    *p2 = (char*)malloc(20);  //分配得來的20字節區域在堆上。
    strcpy(p1,"123456");   //123456\0放在常量區,編譯器可能會將它與p3所向"123456\0"優化成一個地方。
}

//const 常量 或右值常量如"123456"放在數據段還是代碼段??

malloc與free是C++/C語言的標準庫函數,new/delete是C++的運算符。它們都可用于申請動態內存和釋放內存。但是new/delete會調用對象的構造和析構函數。

到此,相信大家對“進程棧、線程棧、內核棧分別是什么”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

黑龙江省| 林西县| 镇雄县| 洛阳市| 北海市| 永胜县| 名山县| 黔江区| 富宁县| 泾川县| 华阴市| 县级市| 和田县| 卢湾区| 若尔盖县| 巨野县| 白银市| 海阳市| 旬邑县| 平湖市| 栾川县| 义马市| 色达县| 邯郸市| 大同市| 三明市| 新巴尔虎左旗| 昌邑市| 横峰县| 黄梅县| 长泰县| 晋州市| 台湾省| 长阳| 芦山县| 舞阳县| 祁门县| 河西区| 陕西省| 濮阳县| 彩票|