色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

從 Linux 內核的角度談線程棧和進程棧

454398 ? 來源: Chinaunix ? 作者:lvyilong316 ? 2020-09-25 15:23 ? 次閱讀

1.進程棧

進程棧是屬于用戶態棧,和進程虛擬地址空間(Virtual Address Space)密切相關。那我們先了解下什么是虛擬地址空間:在32位機器下,虛擬地址空間大小為4G。這些虛擬地址通過頁表(Page Table)映射到物理內存,頁表由操作系統維護,并被處理器的內存管理單元(MMU)硬件引用。每個進程都擁有一套屬于它自己的頁表,因此對于每個進程而言都好像獨享了整個虛擬地址空間。

Linux內核將這4G字節的空間分為兩部分,將最高的1G字節(0xC0000000-0xFFFFFFFF)供內核使用,稱為內核空間。而將較低的3G字節(0x00000000-0xBFFFFFFF)供各個進程使用,稱為用戶空間。每個進程可以通過系統調用陷入內核態,因此內核空間是由所有進程共享的。雖然說內核和用戶態進程占用了這么大地址空間,但是并不意味它們使用了這么多物理內存,僅表示它可以支配這么大的地址空間。它們是根據需要,將物理內存映射到虛擬地址空間中使用。

Linux對進程地址空間有個標準布局,地址空間中由各個不同的內存段組成(Memory Segment),主要的內存段如下:
-程序段(Text Segment):可執行文件代碼的內存映射
-數據段(Data Segment):可執行文件的已初始化全局變量的內存映射
- BSS段(BSS Segment):未初始化的全局變量或者靜態變量(用零頁初始化)
-堆區(Heap) :存儲動態內存分配,匿名的內存映射
-棧區(Stack) :進程用戶空間棧,由編譯器自動分配釋放,存放函數的參數值、局部變量的值等
-映射段(Memory Mapping Segment):任何內存映射文件

而上面進程虛擬地址空間中的棧區,正指的是我們所說的進程棧。進程棧的初始化大小是由編譯器和鏈接器計算出來的,但是棧的實時大小并不是固定的,Linux內核會根據入棧情況對棧區進行動態增長(其實也就是添加新的頁表)。但是并不是說棧區可以無限增長,它也有最大限制RLIMIT_STACK (一般為8M),我們可以通過ulimit來查看或更改RLIMIT_STACK的值。

【擴展閱讀】:進程棧的動態增長實現

進程在運行的過程中,通過不斷向棧區壓入數據,當超出棧區容量時,就會耗盡棧所對應的內存區域,這將觸發一個缺頁異常(page fault)。通過異常陷入內核態后,異常會被內核的expand_stack()函數處理,進而調用acct_stack_growth()來檢查是否還有合適的地方用于棧的增長。

如果棧的大小低于RLIMIT_STACK(通常為8MB),那么一般情況下棧會被加長,程序繼續執行,感覺不到發生了什么事情,這是一種將棧擴展到所需大小的常規機制。然而,如果達到了最大棧空間的大小,就會發生 棧溢出(stack overflow),進程將會收到內核發出的 段錯誤(segmentation fault) 信號。

動態棧增長是唯一一種訪問未映射內存區域而被允許的情形,其他任何對未映射內存區域的訪問都會觸發頁錯誤,從而導致段錯誤。一些被映射的區域是只讀的,因此企圖寫這些區域也會導致段錯誤。

2.線程棧

從Linux內核的角度來說,其實它并沒有線程的概念。Linux把所有線程都當做進程來實現,它將線程和進程不加區分的統一到了task_struct中。線程僅僅被視為一個與其他進程共享某些資源的進程,而是否共享地址空間幾乎是進程和Linux中所謂線程的唯一區別。線程創建的時候,加上了CLONE_VM標記,這樣線程的內存描述符將直接指向父進程的內存描述符。

點擊(此處)折疊或打開

if(clone_flags&CLONE_VM){

/*

*current 是父進程而 tsk 在 fork()執行期間是共享子進程

*/

atomic_inc(¤t->mm->mm_users);

tsk->mm=current->mm;

}

雖然線程的地址空間和進程一樣,但是對待其地址空間的stack還是有些區別的。對于Linux進程或者說主線程,其stack是在fork的時候生成的,實際上就是復制了父親的stack空間地址,然后寫時拷貝(cow)以及動態增長。然而對于主線程生成的子線程而言,其stack將不再是這樣的了,而是事先固定下來的,使用mmap系統調用(實際上是進程的堆的一部分),它不帶有VM_STACK_FLAGS標記。這個可以從glibc的nptl/allocatestack.c中的allocate_stack()函數中看到:

點擊(此處)折疊或打開

mem=mmap(NULL,size,prot,MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK,-1,0);

由于線程的mm->start_stack棧地址和所屬進程相同,所以線程棧的起始地址并沒有存放在task_struct中,應該是使用pthread_attr_t中的stackaddr來初始化task_struct->thread->sp(sp指向struct pt_regs對象,該結構體用于保存用戶進程或者線程的寄存器現場)。這些都不重要,重要的是,線程棧不能動態增長,一旦用盡就沒了,這是和生成進程的fork不同的地方。由于線程棧是從進程的地址空間中map出來的一塊內存區域,原則上是線程私有的。但是同一個進程的所有線程生成的時候淺拷貝生成者的task_struct的很多字段,其中包括所有的vma,如果愿意,其它線程也還是可以訪問到的,于是一定要注意。

3.進程棧和線程棧大小的調整

進程和線程的棧分別是多大呢?首先從我們熟悉的ulimit -s說起,熟悉linux的人都應該知道通過ulimit -s可以修改棧的大小,除此之外還有getrlimit/setrlimit兩個函數:

點擊(此處)折疊或打開

intgetrlimit(intresource,struct rlimit*rlim);

intsetrlimit(intresource,conststruct rlimit*rlim);

這兩個函數當第一個參數傳入RLIMIT_STACK時,可以設置和獲取棧的大小,其作用和ulimit -s是一樣的,只是單位不同,ulimit -s的單位是kB,而這兩個函數的單位是B(字節),詳細使用方法請參考man手冊。

最后還有線程的pthread_attr_setstacksize/pthread_attr_getstacksize。

使用setrlimit和使用ulimit -s設置棧大小效果相同,這兩種方式都是針對進程棧大小設置,只不過前者只真對當前進程,后者針對當前shell;

而線程棧大小的關系就相對比較復雜點,前文說過線程大小是靜態的,是在創建時就確定了的,當然如果使用pthread_attr_setstacksize可以在創建線程時指定線程棧大小,但如果不指定線程棧的話其默認大小是什么情況呢?想要了解線程棧的大小就要看glibc的線程創建函數,具體就是pthread_create->__pthread_create_2_1->allocate_stack。具體代碼還是比較復雜的,這里簡化為一個偽代碼:

點擊(此處)折疊或打開

limit=getlimit(RLIMIT_STACK)

if(limit==RLIMIT_INFINITY)

thread.rlimit=ARCH_STACK_DEFAULT_SIZE//2M

elseifthread.rlimit

thread.rlimit=PTHREAD_STACK_MIN

可以看出,線程默認棧大小和進程棧大小的關系:

1)如果ulimit(setrlimit)設置大小大于16k,則線程棧默認大小由ulimit(setrlimit)決定;

2)如果ulimit(setrlimit)設置大小小于16k,則線程棧默認大小為16;

3)如果ulimit(setrlimit)設置大小為無限制,則線程棧默認大小為2M;

所以我們如果使用ulimit設置進程棧大小是無限大其實棧大小反而相對比較小,這是為什么呢?前面我們已經講過線程棧和進程棧的位置不同,線程棧其實是在進程的堆上分配的,并且不會動態增加,所以不可能設置一個無限大小的線程棧。

最后,我們再對進程棧和線程棧做一下總結和說明:

(1)ulimit -s決定進程棧的大小,但不是嚴格相等(實際測試稍大于ulimit -s設置;

(2)創建線程時如果通過pthread_attr_setstacksize設置了線程棧大小,則使用該屬性創建的線程棧大小就為其設置的值,但不影響線程默認屬性的棧大小值,也不影響ulimit -s的值。

(3)線程一旦創建就無法在修改其棧大小了,即使使用setrlimit。

(4)pthread_attr_setstacksize/pthread_attr_getstacksize的作用是獲取和設置線程屬性中的棧大小的,而不獲取設置線程棧大小的。可以再創建前設置好線程屬性,這樣使用該屬性創建線程就能影響線程的棧大小了。但通過pthread_attr_init,pthread_attr_getstacksize是無法獲取當前線程棧大小的,只能獲取默認屬性的線程棧大小,其值未必就是當前線程棧大小。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • Linux
    +關注

    關注

    87

    文章

    11320

    瀏覽量

    209845
  • 線程
    +關注

    關注

    0

    文章

    505

    瀏覽量

    19705
  • 內存映射
    +關注

    關注

    0

    文章

    14

    瀏覽量

    7438
  • 進程
    +關注

    關注

    0

    文章

    203

    瀏覽量

    13965
收藏 人收藏

    評論

    相關推薦

    Linux網絡原理與實現

    本文嘗試技術研發與工程實踐(而非純理論學習)角度,在原理與實現、監控告警、 配置調優三方面介紹內核5.10 網絡。由于內容非常多,因此分為了幾篇系列文章。
    發表于 08-10 08:58 ?3776次閱讀

    進程線程的區別

    應用程序提供多個線程執行控制。 邏輯角度來看,多線程的意義在于一個應用程序中,有多個執行部分可以同時執行。但操作系統并沒有將多個線程看做多
    發表于 12-12 09:28

    請問uCOS-II中的任務是進程還是線程?

    個提問,然后上面的定義是百度的。按照定義任務應該是進程。有沒大佬rtos的角度剖析一下進程線程的區別。
    發表于 06-03 05:07

    有關Linux系統的PBC (進程控制塊)基礎知識介紹

    ,比如打開的文件,掛起的信號,處理器狀態,內核數據結構,內存映射地址空間等。在操作系統中,內核的調度對象時線程,而不是進程線程
    發表于 06-23 16:27

    用一個實例展示一下Linux內核幀的入和退過程

    1、Linux內核調試方法總結之幀  幀  幀和指針可以說是C語言的精髓。幀是一種特殊的
    發表于 11-04 15:47

    基于STM32的虛擬多線程(TI_BLE協議_ZStack協議)

    基于STM32的虛擬多線程,可以很好的用于裸機程序中,用于模擬小型操作系統的多線程概念。本實例參考了參考TI_BLE協議_ZStack協議。
    發表于 06-14 10:42 ?6940次閱讀
    基于STM32的虛擬多<b class='flag-5'>線程</b>(TI_BLE協議<b class='flag-5'>棧</b>_ZStack協議<b class='flag-5'>棧</b>)

    一文詳解Linux內核回溯與妙用

    網上或多或少都能找到回溯的一些文章,但是講的都并不完整,沒有將內核回溯的功能用于實際的內核、應用程序調試,這是本篇文章的核心:盡可能引導讀者將
    的頭像 發表于 10-05 10:02 ?5411次閱讀
    一文詳解<b class='flag-5'>Linux</b><b class='flag-5'>內核</b>的<b class='flag-5'>棧</b>回溯與妙用

    Linux進程內核的認識

    在每一個進程的生命周期中,必然會通過到系統調用陷入內核。在執行系統調用陷入內核之后,這些內核代碼所使用的并不是原先用戶空間中的
    發表于 05-12 08:53 ?627次閱讀
    對<b class='flag-5'>Linux</b>的<b class='flag-5'>進程</b><b class='flag-5'>內核</b><b class='flag-5'>棧</b>的認識

    淺談鴻蒙內核源碼的

    上面的代碼和鴻蒙內核方式一樣,都采用了遞減滿的方式, 什么是遞減滿?
    的頭像 發表于 04-24 11:21 ?1452次閱讀
    淺談鴻蒙<b class='flag-5'>內核</b>源碼的<b class='flag-5'>棧</b>

    Linux線程進程的區別

    不同的任務。在Unix System V及SunOS中也被稱為輕量進程(lightweight processes),但輕量進程更多指內核線程(kernel thread),而把用戶
    的頭像 發表于 08-24 15:37 ?1877次閱讀
    <b class='flag-5'>Linux</b>下<b class='flag-5'>線程</b>與<b class='flag-5'>進程</b>的區別

    Linux中的進程、線程、內核以及中斷

    首先, (stack) 是一種串列形式的 數據結構。這種數據結構的特點是 后入先出 (LIFO, Last In First Out),數據只能在串列的一端 (稱為:頂 top) 進行 推入
    的頭像 發表于 05-14 09:30 ?716次閱讀
    <b class='flag-5'>Linux</b>中的<b class='flag-5'>進程</b><b class='flag-5'>棧</b>、<b class='flag-5'>線程</b><b class='flag-5'>棧</b>、<b class='flag-5'>內核</b><b class='flag-5'>棧</b>以及中斷<b class='flag-5'>棧</b>

    系統調用:用戶內核的切換(上)

    當發生系統調用、產生異常,外設發生中斷等事件時,會發生用戶內核之間的切換, 本文系統調用角度分析用戶
    的頭像 發表于 07-31 11:27 ?891次閱讀
    系統調用:用戶<b class='flag-5'>棧</b>與<b class='flag-5'>內核</b><b class='flag-5'>棧</b>的切換(上)

    linux中的進程,線程,內核的區別

    大多數的處理器架構,都有實現硬件。有專門的指針寄存器,以及特定的硬件指令來完成 入/出 的操作。例如在 ARM 架構上,R13 (SP) 指針是堆棧指針寄存器,而 PUSH 是
    發表于 08-18 10:57 ?526次閱讀
    <b class='flag-5'>linux</b>中的<b class='flag-5'>進程</b><b class='flag-5'>棧</b>,<b class='flag-5'>線程</b><b class='flag-5'>棧</b>,<b class='flag-5'>內核</b><b class='flag-5'>棧</b>的區別

    ethernetif_input和tcpip協議線程的作用

    tcpip協議線程是lwIP協議的核心線程,負責處理TCP/IP協議的各種功能,包括TCP連接管理、IP數據報的路由和轉發、以及UDP
    的頭像 發表于 03-20 10:01 ?1394次閱讀

    Linux網絡協議的實現

    網絡協議是操作系統核心的一個重要組成部分,負責管理網絡通信中的數據包處理。在 Linux 操作系統中,網絡協議(Network Stack)負責實現 TCP/IP 協議簇,處理應用程序發起的網絡
    的頭像 發表于 09-10 09:51 ?330次閱讀
    <b class='flag-5'>Linux</b>網絡協議<b class='flag-5'>棧</b>的實現
    主站蜘蛛池模板: 亚洲欧美成人| AV多人爱爱XXx| 国产成人欧美日韩在线电影 | 87影院午夜福利| 美女伸开两腿让我爽| 99久久免费精品国产| 人妻免费久久久久久久了| 国产爱豆果冻传媒在线观看视频| 亚洲成人免费在线| 麻豆一区二区三区蜜桃免费| 电影果冻传媒在线播放| 亚洲黄色在线观看| 久久久精品3d动漫一区二区三区| CHINSEFUCKGAY无套| 亚洲精品成人a在线观看| 美美哒高清在线播放8| 国产高清视频a在线大全| 一区视频免费观看| 揉抓捏打抽插射免费视频| 精品久久久久久无码人妻国产馆| 99视频久九热精品| 亚洲国产精品一区二区久久第| 美女直播喷水| 国产性夜夜性夜夜爽91| 99RE久久精品国产| 亚洲精品国产自在在线观看| 欧美狂野乱码一二三四区| 回复术士人生重启在线观看| 白人大战34厘米黑人BD| 亚洲中文无码亚洲人在线观看-| 热热久久这里只有精品| 精品视频在线播放| 高H辣肉办公室| 97在线播放| 亚洲一区二区三区乱码在线欧洲| 日本粉嫩学生毛绒绒| 久久欧洲视频| 国产在线精品国自产拍影院午夜| 边做边爱BD免费看片| 最近免费中文MV在线字幕 | 黄色软件色多多|