當前位置: 妍妍網 > 碼農

一個行程最多可以建立多少個執行緒?

2024-02-26碼農


點選上方 Linux開源社群 」,選擇「 設為星標

優質文章,及時送達

轉自:網路

前言

話不多說,先來張腦圖~


linux 虛擬記憶體知識回顧

虛擬記憶體空間長啥樣

在 Linux 作業系統中,虛擬地址空間的內部又被分為 內核空間和使用者空間 兩部份,不同位數的系統,地址空間的範圍也不同。比如最常見的 32 位和 64 位系統,如下所示:


透過這裏可以看出:

  • 32 位系統的內核空間占用 1G,位於最高處,剩下的 3G 是使用者空間;

  • 64 位系統的內核空間和使用者空間都是 128T,分別占據整個記憶體空間的最高和最低處,剩下的中間部份是未定義的。

  • 32 位虛擬記憶體空間


    透過這張圖你可以看到,使用者空間記憶體,從 低到高 分別是 6 種不同的記憶體段:

  • 0x0000 0000 到 0x0804 8000 這段虛擬記憶體地址是一段不可存取的保留區,因為在大多數作業系統中,數值比較小的地址通常被認為不是一個合法的地址,這塊小地址是不允許存取的。比如在 C 語言中我們通常會將一些無效的指標設定為 NULL,指向這塊不允許存取的地址。

  • 程式碼段,包括二進制可執行程式碼;

  • 數據段,包括已初始化的靜態常量和全域變量;

  • BSS 段,包括未初始化的靜態變量和全域變量;

  • 堆段,包括動態分配的記憶體,從低地址開始向上增長;

  • 堆空間的上邊是一段待分配區域,用於擴充套件堆空間的使用

  • 檔對映段,包括動態庫、共享記憶體等,從低地址開始向上增長

  • 棧段,包括局部變量和函式呼叫的上下文等。棧的大小是固定的,一般是 8 MB。當然系統也提供了參數,以便我們自訂大小;

  • 在上面的記憶體段中,堆和檔對映段的記憶體是動態分配的。比如說,使用 C 標準庫的 malloc() 或者 mmap() ,就可以分別在堆和檔對映段動態分配記憶體。

    64 位虛擬記憶體空間

    我們知道在 32 位機器上,指標的尋址範圍為 2^32,所能表達的虛擬記憶體空間為 4 GB。

    那麽我們可能會認為在 64 位機器上,指標的尋址範圍為 2^64,所能表達的虛擬記憶體空間為 16 EB 。虛擬記憶體地址範圍為:0x0000 0000 0000 0000 0000 - 0xFFFF FFFF FFFF FFFF 。

    事實上在目前的 64 位系統下只使用了 48 位來描述虛擬記憶體空間,尋址範圍為 2^48 ,所能表達的虛擬記憶體空間為 256TB。


    從上圖中我們可以看出 64 位系統中的虛擬記憶體布局和 32 位系統中的虛擬記憶體布局大體上是差不多的。微信搜尋公眾號:架構師指南,回復:架構師 領取資料 。

    建立一個執行緒需要消耗多大虛擬記憶體

    前面我們也介紹了 棧段,包括局部變量和函式呼叫的上下文等。棧的大小是固定的,一般是 8 MB。當然系統也提供了參數,以便我們自訂大小;

    現在我們來驗證一下,執行 ulimit -a 這條命令,檢視行程建立執行緒時預設分配的棧空間大小


    影響一個行程可建立多少執行緒的條件

  • 行程的虛擬記憶體空間上限 ,因為建立一個執行緒,作業系統需要為其分配一個棧空間,如果執行緒數量越多,所需的棧空間就要越大,那麽虛擬記憶體就會占用的越多。

  • 系統參數限制 ,雖然 Linux 並沒有內核參數來控制單個行程建立的最大執行緒個數,但是有系統級別的參數來控制整個系統的最大執行緒個數。

  • 虛擬記憶體空間上限

    32位元系統

    在 32 位 Linux 系統裏,一個行程的虛擬空間是 4G,內核分走了1G, 使用者能用的只有 3G

    建立一個執行緒需要占用 8M 虛擬記憶體,總共有 3G 虛擬記憶體可以使用。於是我們可以算出,最多可以建立差不多 380個(3G/8M)左右的執行緒。

    如果想使得行程建立上千個執行緒,那麽我們可以調整建立執行緒分時配的棧空間大小,比如調整為 512k:

    [ecs-user@iZ2ze923utbhhwxwgc0pd9Z ~]$ ulimit -s 512

    64位元系統

    64 位系統意味著使用者空間的虛擬記憶體最大值是 128T,這個數值是很大的,一個執行緒需占用 8M 棧空間的情況來算,那麽理論上可以建立 128T/8M 個執行緒,也就是 1000多萬個執行緒,有點魔幻!

    所以按 64 位系統的虛擬記憶體大小,理論上可以建立無數個執行緒。

    系統參數限制

    前面學習我們了解到了64 位系統的虛擬記憶體大小,理論上可以建立無數個執行緒。不過事實上,肯定建立不了那麽多執行緒,除了虛擬記憶體的限制,還有系統的限制。

    比如下面這三個內核參數的大小,都會影響建立執行緒的上限:

  • /proc/sys/kernel/threads-max ,表示系統支持的最大執行緒數,預設值是 14553;

  • /proc/sys/kernel/pid_max ,表示系統全域的 PID 號數值的限制,每一個行程或執行緒都有 ID,ID 的值超過這個數,行程或執行緒就會建立失敗,預設值是 32768;

  • /proc/sys/vm/max_map_count ,表示限制一個行程可以擁有的VMA(虛擬記憶體區域)的數量,具體什麽意思我也沒搞清楚,反正如果它的值很小,也會導致建立執行緒失敗,預設值是 65530。

  • 總結

    最後簡單總結下:

  • 32 位系統,使用者態的虛擬空間只有 3G,預設建立執行緒分時配的棧空間是 8M,那麽一個行程最多只能建立 380 個左右的執行緒。

  • 64 位系統,使用者態的虛擬空間大到有 128T,理論上不會受虛擬記憶體大小的限制,而會受系統的參數或效能限制。

  • -End-

    讀到這裏說明你喜歡本公眾號的文章,歡迎 置頂(標星)本公眾號 Linux技術迷,這樣就可以第一時間獲取推播了~

    本公眾號,後台回復:Linux,領取2T學習資料 !

    1. 

    2. 

    3.

    4.