Virtual-Memory

這個程序需要多少頁錯誤?

  • October 9, 2018

作業系統概念說

讓我們看一個人為但內容豐富的例子。假設頁面大小為 128 個字。考慮一個 C 程序,其功能是將 128×128 數組的每個元素初始化為 0。以下程式碼是典型的:

int i, j;
int[128][128] data;
for (j = 0; j < 128; j++)
for (i = 0; i < 128; i++)
data[i][j] = 0;

請注意,該數組儲存的主要是行;也就是說,數組是儲存數據

$$ 0 $$$$ 0 $$, 數據$$ 0 $$$$ 1 $$, · · ·, 數據$$ 0 $$$$ 127 $$, 數據$$ 1 $$$$ 0 $$, 數據$$ 1 $$$$ 1 $$, · · ·, 數據$$ 127 $$$$ 127 $$. 對於 128 個單詞的頁面,每行佔一頁。因此,前面的程式碼將每一頁中的一個字歸零,然後每一頁中的另一個字歸零,以此類推。如果作業系統為整個程序分配的幀少於 128 個,那麼它的執行將導致 128 × 128 = 16,384 個頁面錯誤。

高亮中的那句話是不是表示在初始化數組的每個元素時,都會發生頁面錯誤,並且在頁面替換和元素初始化之後,頁面會立即移出RAM?

“作業系統為整個程序分配的幀少於 128 個”並不一定意味著“作業系統為整個程序分配一個幀”。那麼為什麼文本如此確定,最近的頁面在被訪問後立即移出 RAM 呢?

假設作業系統為程序分配了小於 128 個幀的“n”幀。它可以只保留“n-1”頁,即 RAM 中的行,並將剩餘的一頁用於所有頁面錯誤和替換嗎?那麼頁面錯誤的總數可以從128*128減少到(n-1) + (128-(n-1))*128?

那麼為什麼文本如此確定,最近的頁面在被訪問後立即移出 RAM 呢?

通常,最近最少訪問的頁面將被驅逐,但這確實會導致所描述的病態行為。第一次通過內循環,前n幀被分頁;然後當頁面n + 1需要被調入時,頁面1被調出,這樣就可以確保每次循環時所有頁面都需要調回。

但是,這種情況確實不太可能發生。如果系統完全缺乏 RAM(物理和交換),核心將​​殺死一個程序以釋放一些記憶體;鑑於測試程序的行為,它不太可能成為候選人。如果系統僅缺乏物理 RAM,核心將換出頁面,或減少其記憶體;如果它交換頁面,則不太可能針對測試程序。在這兩種情況下,測試程序都會有足夠的 RAM 來適應它的工作集。如果您確實設法以某種方式僅使測試程序餓死(例如,通過增加其工作集以使其支配系統的記憶體),那麼在實踐中您更有可能看到它被殺死SIGSEGV比您看到它不斷地進出它的工作集。(這很好,這是教科書上的思想實驗。學習由此產生的原理,不一定要嘗試將範例應用到實踐中。)

它可以只保留“n-1”頁,即 RAM 中的行,並將剩餘的一頁用於所有頁面錯誤和替換嗎?

可以*,*但係統這樣做是不尋常的;系統如何知道未來的記憶體訪問模式會是什麼樣子?一般來說,您會看到 LRU 驅逐,因此循環將表現出如上所述的病態行為。

如果你想玩這個,修復程序,使其匹配 4KB 大小的頁面(在 x86 上使用;我假設 Linux 在 64 位 x86 上),並實際編譯:

int main(int argc, char **argv) {
 int i, j;
 int data[128][1024];
 for (j = 0; j < 1024; j++)
   for (i = 0; i < 128; i++)
     data[i][j] = 0;
}

然後使用 執行它/usr/bin/time,它將顯示頁面錯誤的數量:

0.00user 0.00system 0:00.00elapsed 100%CPU (0avgtext+0avgdata 1612maxresident)k
0inputs+0outputs (0major+180minor)pagefaults 0swaps

這種數組處理會導致更多的記憶體行驅逐問題,而不是實際的頁面錯誤。

引用自:https://unix.stackexchange.com/questions/474260