2017-03-17 79 views
1

我想了解內存使用情況的兩個細節,以及如何使用C++來測量它。我知道,在Windows下,正在使用的當前應用程序,檢索的RAM數量的快速方法包括<Windows.h>時,就是:無法使用GetProcessMemoryInfo測量靜態數組的內存使用情況

PROCESS_MEMORY_COUNTERS info; 
GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)); 
(uint64_t)info.WorkingSetSize; 

然後,我用的是運行一個非常簡單的測試:

#include <iostream> 
#include <Windows.h>" 

int main(void) 
{ 
    uint64_t currentUsedRAM(0); 

    PROCESS_MEMORY_COUNTERS info; 
    GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)); 
    currentUsedRAM = info.WorkingSetSize; 

    const int N(1000000); 
    int x[N]; //in the second run, comment this line out 
    int y[N]; //in the second run, comment this line out 
    //int *x = new int[N]; //in the second run UNcomment this line out 
    //int *y = new int[N]; //in the second run UNcomment this line out 
    for (int i = 0; i < N; i++) 
    { 
     x[i] = 1; 
     y[i] = 2; 
    } 

    GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)); 
    currentUsedRAM = info.WorkingSetSize - currentUsedRAM; 

    std::cout << "Current RAM used: " << currentUsedRAM << "\n"; 

    return 0; 
} 

當我運行上面的代碼時,輸​​出結果是:Current RAM used: 0,而我期待8mb左右的數據,因爲我填充了兩個每個有100萬條記錄的1D int數組。現在,如果我重新運行代碼,但使xy成爲dinamically分配的陣列,現在輸出如預期:Current RAM used: 8007680

這是爲什麼?如何在兩種情況下檢測內存使用情況?

+0

我很驚訝你的程序甚至開始,因爲你爲這兩個數組分配了近8兆內存。 Windows上的默認堆棧大小通常是一個MB。有了這個,你也應該知道你爲什麼沒有得到預期的結果。 –

+0

@Someprogrammerdude這完全是**我的疑問。我的直覺正是這個函數只是測量堆中的內存分配,而不是堆棧中的內存分配。但是,由於應用程序運行,我無法理解發生了什麼。所以,這只是該函數只能獲得堆內存使用。有沒有辦法計算堆棧內存使用情況? –

+0

編譯已經優化了這兩個數組。你可以做一些副作用來防止這種情況:嘗試輸出他們元素的總和。 – felix

回答

0

編譯器已優化您的代碼。如果事實上,對於你的第一次運行,x或y都沒有被分配。考慮到有可見的副作用:GetProcessMemoryInfo的返回值,這種優化看起來有點奇怪。

無論如何,您可以通過添加一些其他副作用來防止這種情況,例如輸出這兩個數組中每個元素的總和,這將防止崩潰。

爲具有自動存儲持續時間的本地對象分配內存at the beginning of the enclosing code block and deallocated at the end。所以你的代碼不能測量main中的任何自動sotrage持續時間變量(也不是我刪除的代碼片斷,我沒有聽說過)的內存使用情況。但對於具有動態存儲持續時間的對象,情況會有所不同,它們是按請求分配的。


我設計了一個測試,涉及評論區的討論recusion。如果程序更深入,您可以看到內存使用量增加。這證明它計算了堆棧上的memroy使用情況。順便說一句,它不計算你的對象需要多少內存,但你的程序需要多少。

void foo(int depth, int *a, int *b, uint64_t usage) { 
    if (depth >= 100) 
    return ; 
    int x[100], y[100]; 

    for (int i = 0; i < 100; i++) 
    { 
    x[i] = 1 + (a==nullptr?0:a[i]); 
    y[i] = 2 + (b==nullptr?0:b[i]); 
    } 

    PROCESS_MEMORY_COUNTERS info; 
    GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)); 

    std::cout << "Current RAM used: " << info.WorkingSetSize - usage << "\n"; 

    foo(depth+1,x,y,usage); 

    int sum = 0; 
    for (int i=0; i<100; i++) 
    sum += x[i] + y[i]; 

    std::cout << sum << std::endl; 
} 

int main(void) 
{ 
    uint64_t currentUsedRAM(0); 
    PROCESS_MEMORY_COUNTERS info; 
    GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)); 
    currentUsedRAM = info.WorkingSetSize; 

    foo(0, nullptr, nullptr, currentUsedRAM); 

    return 0; 
} 

/* 
Current RAM used: 0 
Current RAM used: 61440 
Current RAM used: 65536 
Current RAM used: 65536 
Current RAM used: 65536 
Current RAM used: 65536 
Current RAM used: 69632 
Current RAM used: 69632 
Current RAM used: 69632 
Current RAM used: 69632 
Current RAM used: 69632 
Current RAM used: 73728 
*/ 

系統每次分配4k,這是一個頁面的大小。我不知道爲什麼會出現0,然後突然出現61440.解釋Windows如何管理內存非常困難,而且遠遠超出了我的能力,儘管我對4k的東西有信心......並且它確實計算了內存使用情況對於自動存儲持續時間的變量。

+0

我猜想改變N不會改變當前使用的RAM,因爲堆棧的大小是固定的。 – felix

+0

我不這麼認爲。嘗試將循環的迭代次數從1增加到可以達到的最高值(即250000左右)。您將看到所使用的RAM數量不會改變。您正在捕獲的RAM與創建的陣列無關。數組不計數,因爲它全部在堆棧和函數中,我猜測只計數堆內存。由於令人難以置信的「std :: cout」調用,您獲得RAM使用的數量是全部的。如果你註釋掉其他所有內容,只留下一個'std :: cout << 1 << std :: endl',你將獲得相同的內存使用量。 –

+0

(抱歉,我試圖編輯它時意外刪除了第一條評論,但現在我對我之前所說的內容充滿信心,因爲正如您在上面的新評論中看到的,我已經對它進行了測試。等着瞧) –