Linux-Kernel
載入可執行目標文件並創建私有區域
我正在閱讀一本關於虛擬記憶體的教科書,上面寫著:
任何 Linux 程序都可以通過呼叫以下
execve
函式來呼叫載入程序:
- 刪除目前程序虛擬地址的使用者部分中的現有區域結構。
- 為新程序的程式碼、數據、bss 和堆棧區域創建新的區域結構。所有這些新區域都是私有的寫時複製。程式碼和數據區域映射到 a.out 文件的 .text 和 .data 部分
我只是在想如果該程序是一個單程序程序(不使用
fork()
),當這個單程序從假設的.data
部分中的虛擬地址開始時a.out
,它將觸發保護錯誤,然後錯誤處理程序會注意到保護異常是由程序嘗試寫入私有寫時複製區域中的頁面引起的,它會在物理記憶體中創建該頁面的新副本。我在這裡看到兩個問題:
- 即使沒有第二個程序可以共享物理記憶體中的同一頁,私有區域的寫時複製機制仍然會創建一個新頁,這根本沒有用,因為只有一個程序,沒有其他程序會寫到這個頁面,每次程序要修改一個頁面都會觸發一個異常來處理,效率相當低?
- 在物理記憶體中創建了一個新的頁面副本,那麼程序不再引用的原始頁面呢?如果舊頁面駐留在物理記憶體中,那不是浪費記憶體嗎?
您遺漏了一條關鍵資訊:當核心處理與寫時複製方案相對應的頁面錯誤時,如果目標頁面由單個程序使用,它會使頁面可寫而不是複制它。
核心為每個頁面保留一個計數器,
mapcount
在struct page
; 如果單個程序映射頁面,則該計數器為 0,並且在每次新程序映射它時遞增,並在它未映射時遞減(例如,因為它是寫時複製並且程序試圖寫入它)。