與程序相關的堆棧是什麼意思?
從Unix 環境中的高級程式一書中,我閱讀了以下關於類 Unix 系統中的執行緒的行
一個程序中的所有執行緒共享相同的地址空間、文件描述符、堆棧和程序相關屬性。因為它們可以訪問相同的記憶體,執行緒之間需要同步訪問共享數據以避免不一致。
作者
stacks
在這裡是什麼意思?我從事 Java 程式並且知道每個執行緒都有自己的堆棧。所以我對這裡的共享stacks
概念感到困惑。
在 Unix 或 linux 程序的上下文中,片語“堆棧”可能意味著兩件事。
首先,“棧”可以表示控制流呼叫序列的後進先出記錄。當一個程序執行時,
main()
首先被呼叫。main()
可能會打電話printf()
。編譯器生成的程式碼將格式字元串的地址和任何其他參數寫入printf()
某些記憶體位置。然後程式碼寫入完成後控制流應該返回的地址printf()
。然後程式碼呼叫跳轉或分支到printf()
. 每個執行緒都有這些函式啟動記錄堆棧之一。請注意,許多 CPU 具有用於設置和維護堆棧的硬體指令,但其他 CPU(IBM 360 或其他名稱)實際上使用了可能分散在地址空間中的鍊錶。其次,“堆棧”可以表示 CPU 將參數寫入函式的記憶體位置,以及被呼叫函式應返回的地址。“堆棧”是指程序地址空間的連續部分。
Unix、Linux 或 *BSD 程序中的記憶體是一條很長的線,從大約 0x400000 開始,到大約 0x7fffffffffff 結束(在 x86_64 CPU 上)。堆棧地址空間從最大的數字地址開始。每次呼叫函式時,函式 activatio 記錄的堆棧都會“向下增長”:程序程式碼將函式參數和返回地址放在 activatio 記錄的堆棧上,並遞減堆棧指針,堆棧指針是一個特殊的 CPU 寄存器,用於跟踪在堆棧的地址空間中,程序目前變數的值所在的位置。
每個執行緒都獲得一塊“堆棧”(堆棧地址空間)供自己用作函式啟動記錄堆棧。在 0x7ffffffffffff 和較低地址之間的某個位置,每個執行緒都有一個記憶體區域保留用於函式呼叫。通常這只是由約定而不是硬體強制執行的,因此如果您的執行緒在嵌套函式之後呼叫函式,則該執行緒堆棧的底部可能會覆蓋另一個執行緒堆棧的頂部。
所以每個執行緒都有一塊“堆棧”記憶體區域,這就是“共享堆棧”術語的來源。這是程序地址空間是單個線性記憶體塊的結果,以及術語“堆棧”的兩種用法。我很確定實際上一些較舊的 JVM(非常古老)只有一個執行緒。Java 程式碼中的任何執行緒實際上都是由單個真實執行緒完成的。較新的 JVM,即呼叫真正執行緒來執行 Java 執行緒的 JVM,將具有我上面描述的相同的“共享堆棧”。Linux 和 Plan 9 有一個程序啟動系統呼叫(Linux 的 clone(),Plan 9 中的 rfork()),它可以設置共享部分地址空間的程序,可能還有不同的堆棧地址空間,但這種執行緒風格從未真正流行起來。