2011-06-11 82 views
5

我一直在努力弄清楚爲什麼我的程序消耗了太多的系統RAM。我正在從磁盤加載一個文件到幾個動態分配數組的結構向量中。根據任務管理器,一個16MB文件最終會消耗280MB的系統RAM。文件中的類型主要是一些短褲和幾條長褲。該文件中有331,000條記錄平均包含大約5個字段。我將矢量轉換爲結構,並將內存減少到約255MB,但仍然看起來非常高。隨着矢量佔用大量內存,程序內存不足,所以我需要找到一種更合理的內存使用方式。爲什麼存儲5MB數據的VC++程序會佔用64MB系統內存?

我寫了一個簡單的程序來填充一個帶有1,000,000個char指針的向量(或數組)。我希望它爲每個存儲需要5MB內存分配4 + 1字節,但實際上它使用64MB(陣列版本)或67MB(矢量版本)。當程序第一次啓動時,它只消耗了400K,爲什麼還有一個額外的59MB的陣列或62MB的矢量被分配?這額外的內存似乎是爲每個容器,所以如果我創建一個size_check2並複製所有內容並運行它,程序使用了135MB的指針和數據10MB的價值。

由於提前,

size_check.h

#pragma once 

#include <vector> 

class size_check 
{ 
public: 
    size_check(void); 
    ~size_check(void); 

    typedef unsigned long size_type; 

    void stuff_me(unsigned int howMany); 

private: 
    size_type**   package; 
// std::vector<size_type*> package; 
    size_type*   me; 
}; 

size_check.cpp

#include "size_check.h" 

size_check::size_check(void) 
{ 
} 

size_check::~size_check(void) 
{ 
} 

void size_check::stuff_me(unsigned int howMany) 
{ 
    package = new size_type*[howMany]; 
    for(unsigned int i = 0; i < howMany; ++i) 
    { 

     size_type *me = new size_type; 
     *me = 33; 
     package[i] = me; 
//  package.push_back(me); 
    } 
} 

的main.cpp 的#include 「size_check.h」

int main(int argc, char * argv[ ]) 
{ 
    const unsigned int buckets = 20; 
    const unsigned int size = 50000; 

    size_check* me[buckets]; 

    for(unsigned int i = 0; i < buckets; ++i) 
    { 
     me[i] = new size_check(); 
     me[i]->stuff_me(size); 
    } 
    printf("done.\n"); 
} 
+0

我還沒有詳細閱讀你的代碼,但請記住,指針也佔用空間。 – slartibartfast 2011-06-11 02:48:07

+0

您還需要考慮數據結構對齊和填充。 – feathj 2011-06-11 02:52:14

+0

@myrkos是正確的 - 如果我沒有記錯的話,在公共硬件上有四個字節。你的班級定義也需要空間。試着做一個你製作的size_check對象的sizeof(),然後把它乘以你創建的實例的數目,看看它是否不能彌補差異。 – 2011-06-11 02:55:11

回答

3

在我的測試中使用VS2010,調試版本的工作集大小爲52,500KB。但是發佈版本的工作集爲,大小爲20,944KB。

由於調試堆管理器執行諸如創建memory fences之類的操作,調試構建通常會使用比優化構建更多的內存。

在發佈版本中,我懷疑堆管理器會保留比實際用作性能優化更多的內存。

+1

@Mark:當你問一個問題並且有人回答時,不要編輯答案來添加你自己的評論;這很混亂。使用您想評論的答案下方的添加評論鏈接。 – 2011-06-12 05:53:52

1

內存泄漏

package = new size_type[howMany]; // instantiate 50,000 size_type's 
for(unsigned int i = 0; i < howMany; ++i) 
{ 
    size_type *me = new size_type; // Leak: results in an extra 50k size_type's being instantiated 
    *me = 33; 
    package[i] = *me; // Set a non-pointer to what is at the address of pointer "me" 
    // Would package[i] = 33; not suffice? 
} 

此外,確保你已經在釋放模式編譯

1

有可能是你爲什麼看不到這麼大的內存佔用幾個原因你測試程序。裏面你

void size_check::stuff_me(unsigned int howMany) 
{ 

此方法總是得到調用howMany = 50000

package = new size_type[howMany]; 

假設這是一個32位的設置上面的語句將分配50000個* 4字節。

for(unsigned int i = 0; i < howMany; ++i) 
{ 
    size_type *me = new size_type; 

以上將在循環的每次迭代中分配新的存儲空間。由於這循環50,000,分配永遠不會被刪除,循環完成後有效地佔用另外的50,000 * 4字節。

 *me = 33; 
     package[i] = *me; 
    } 
} 

最後,由於stuff_me()會從main()稱爲20倍的計劃將有至少〜8Mbytes完成後分配。如果這是在64位系統上,那麼從sizeof(long) == 8bytes起,佔用空間可能會翻倍。

內存消耗的增加可能與VS實現動態分配的方式有關。出於性能原因,可能由於多次調用new,程序會預留額外的內存,以避免每次需要更多操作時觸發操作系統。當我在mingw-gcc 4.5.2上運行你的測試程序時,內存消耗約爲20M字節 - 遠遠低於你所看到的,但仍然是一個相當大的數量。如果我將stuff_me方法更改爲:

void size_check::stuff_me(unsigned int howMany) 
{ 
    package = new size_type[howMany]; 
    size_type *me = new size_type; 
    for(unsigned int i = 0; i < howMany; ++i) 
    { 
     *me = 33; 
     package[i] = *me; 
    } 
    delete me; 
} 

內存消耗降低到約4-5mbytes。

1

我想我通過研究新的陳述找到答案。在調試版本中,有兩個項目是在創建新項目時創建的。一個是_CrtMemBlockHeader,它的長度是32個字節。另一個是noMansLand(一個內存圍欄),大小爲4字節,每個新增了36字節的開銷。在我的情況下,每個新的字符都花費了我37個字節。在發佈版本中,內存使用減少到1/2左右,但我無法確切知道每個新版本分配了多少,因爲我無法訪問新的/ malloc例程。

所以我的工作是分配一大塊內存來保存文件在內存中。然後解析存儲器圖像填充到指向每個記錄開頭的指針向量中。然後根據需要,我使用指向所選記錄開頭的指針從記憶圖像構建記錄。這樣做將內存佔用減少到了25MB的<。

感謝您的幫助和建議。

相關問題