new在測驗有關頁面錯誤的一些事情時,我發現在 MSVC 中的除錯模式和發布模式下的操作方式之間存在奇怪的差異。考慮以下代碼1:
#include <array>
constexpr size_t PAGE_SIZE = 4096;
int main()
{
const size_t count = 1000000;
char* const mem = new char[PAGE_SIZE * count];
// page align the pointer, c-style casts used for brevity
auto* pages = (std::array<char, PAGE_SIZE>*)((size_t)mem - (size_t)mem % PAGE_SIZE PAGE_SIZE);
for (int i = 0; i < count; i)
pages[i][0] = 'a';
}
該代碼在大多數架構上分配了一百萬個普通記憶體
紅色時間點是正在啟動的程式,綠色時間點/時間間隔是對 的呼叫new char[],藍色時間點/時間間隔是for回圈。
事實證明,在除錯模式下,程式new“保留”和“給予”記憶體。同時,在釋放模式下,它只“保留”它,因為記憶體是由回圈“給予”的。我只期望發布模式下的行為 - 我認為只有在發生頁面錯誤時才會將記憶體“給予”給程式。
為什么會有這樣的new行為?這有什么重大影響嗎?
1順便說一句,由于某種原因更改auto* pages為auto* const pages會導致內部編譯器錯誤。
2我對正確的術語有點困惑,所以我改用了“given”和“reserved”。
uj5u.com熱心網友回復:
要了解發生了什么,您需要知道兩件事:
- 除錯版本為您做了很多很酷的事情來幫助您找到錯誤。一種是將已知值寫入程式的記憶體中,這樣您就可以更容易地識別出您已經搞砸了未初始化的存盤。
- CPU 中的現代記憶體管理系統很復雜,但他們都傾向于做的一件事是盡可能少,直到不得不這樣做。當程式請求存盤時,底層系統檢查是否有足夠的虛擬尋址空間,然后幾乎總是允許請求而不填充它。沒有找到物理記憶體并將其分配給虛擬記憶體。當訪問記憶體時,將找到并分配物理記憶體,否則程式會因為記憶體不可用而失敗。
第 1 點和第 2 點的組合意味著 debug 版本new通過寫入未初始化的記憶體檢測模式并強制系統在綠色區域中找到并移交真實記憶體來獲取記憶體并立即訪問它。作為一個額外的好處,如果計算機確實用完了物理存盤,程式可能會在這里崩潰,而不是在將來某個看似隨機的點無法滿足請求時。
發布版new不做第1點,所以物理記憶體獲取按照第2點延遲。new快速退出綠色區域,沒有任何物理記憶體。如果部分或全部請求的記憶體從未使用過,則計算機無需執行滿足請求的作業即可獲利。該程式確實在for回圈中使用了請求的存盤空間,因此系統被迫在藍色區域中查找并提供物理記憶體。
uj5u.com熱心網友回復:
除錯new以可識別的模式填充記憶體。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/420588.html
標籤:
