2012-12-28 136 views
1

我正在處理一些有點奇怪的情況,但這正是我計劃創建的。這只是一種特殊的測試軟件...強制Windows釋放分配的內存

我的環境:MSVS 2012,Windows 7/8 32b/64b。

所以,首先我創建了一些內部結構/緩存/等我的應用程序使用,那麼我做這樣的事情(在這裏簡化了一下,請把它有點像僞代碼):

{ 
    std::deque<boost::scoped_array<unsigned char>> deque; 
    try { 
    while (1) { 
     deque.push_back(boost::scoped_array<unsigned char>(new unsigned char[system_page_size])); // happens to be 4096 on my system 
    } 
    } 
    catch (std::bad_alloc& ex) { ... } 
    // do something here 
} 

我需要使用盡可能多的內存。我一次分配整個頁面(也許這很糟糕,應該爲deque/smart ptr的數據留出一些空間?)。當CRT決定不再有可能進行分配時,我會做更多的事情(根本不依賴任何內存可用性),然後退出範圍。它會觸發一連串的析構函數,所有這些數據都應該被釋放。

This works great。但是我碰巧進入這個奇怪的範圍不是一次,而是循環中的10次。它有時會工作2到3次。有時只有一次。下次我只會得到內存不足的錯誤,就是這樣。

從我的角度來看,我需要重新啓動整個過程才能真正強制釋放內存。有沒有一種方法可以在單一過程中實現這一點?

我可以考慮嘗試不同的分配器 - 也許這是CRT問題?我也玩過一些堆操作(即低碎片堆),但也沒有幫助。

+0

你正在分割堆。這是正常的行爲 - 「窗戶」不會爲你留住記憶。你可以直接調用'VirtualAlloc'來完成這個工作。 –

+0

好吧,我分解過程堆,但然後我試圖分配完全相同種類的塊。在這裏我沒有看到問題,因爲在第一個bad_alloc拋出後沒有額外的分配。 – Mickey

回答

0

爲什麼不使用MEM_RESERVE調用一些大型調用VirtualAlloc調用來保留進程的整個內存空間。然後,您將在每個內存範圍稍後調用VirtualFree進行發佈。這仍然需要一些堆分配,就像你在這裏所做的那樣,以消耗當前堆的其餘部分。它會更快,並刪除您必須遇到的頁面文件流失。

至於你的具體問題,我不知道你爲什麼遇到它。保留所有內存以便堆不能擴展應該有助於減少非確定性。

+0

是否有一個很好的方法來計算這幾個大頁面的大小?如果我會問太多,那就會失敗。 – Mickey

+0

您可以通過調用[VirtualQuery](http://msdn.microsoft.com/en-us/library/aa366902%28v=vs)來映射進程的地址空間。85%29.aspx),直到你耗盡了你的地址空間。然後所有的MEM_FREE區域都可以使用VirtualAlloc保留。只需從最小地址開始查詢,並將其長度擴展到最大地址。檢查GetSystemInfo以獲取尋址範圍。 – Avilo

+0

如果這是多線程,我將添加,分配的頁面將會更改,以便VirtualQuery報告空閒範圍時立即保留該地址。保存結果指針以供稍後釋放。您可能想要首先分配一個大型數組來保存這些指針,因爲STL容器會動態地分配每個指針,這可能會因爲內存耗盡而失敗。 – Avilo

0

如果你使用大量的內存,使用某種slab分配(VirtualAlloc會爲你提供內存),然後原則上[假設你創建的對象不需要析構函數做一些事情],你可以一次性扔掉整個塊,而不是使用刪除鉅額代碼 - 同時還可以節省時間以及保證你的內存已經完全釋放。

我懷疑你可能有問題的一個原因是釋放的塊在被回收之前必須被清除。這是在內核的後臺線程中完成的。當然,使用VirtualALloc實際上對此帳戶無幫助。

當然你也可能會得到內存碎片,在這種情況下,使用一個旨在避免這種情況的頭部會起作用。