2014-03-24 15 views
2

我知道其他幾個討論過類似問題的線程。另外我知道,必須釋放所有已分配的資源,並且不應有任何內容不明。我問這個問題的原因是看看是否有辦法在課堂上自動檢測內存泄漏。特別是,我試圖實現一種自動化的方式來檢測單元測試中的泄漏,以便該類的未來開發將更加強大。由於我的課程內部使用了其他幾個類以及一些DLL,因此即使不是不可能跟蹤所有這些漏洞,也是很困難的,所以這樣的單元測試可能會有所幫助。如何檢查C++中的類中的內存泄漏?

我在想一些解決方案能夠檢查課堂內存泄漏。假設我的類是類似於這樣:

class MyClass 
{ 
    MyClass() { /* Lots of allocations */ } 
    ~MyClass() { /* Lots of deallocations */ } 
} 
  1. 在測試功能,實例化類實例多次 ,每次破壞。同時,檢查任務管理器(在 的Windows至少),看看是否已分配的內存爲您 應用斜坡上升或保持基本平:

    TEST(MyClass, MyClass) 
    { 
        int some_big_number = 10000; 
        for (int i=0; i<some_big_number; i++) 
        { 
         MyClass *myC = new MyClass; 
         delete myC; 
        } 
    } 
    
  2. 前後實例化和 破壞後分配一些虛擬變量的類實例並檢查這兩個地址是否相同 。事情是這樣的:

    TEST(MyClass, MyClass) 
    { 
        int address_1 = 0, address_2 = 0; 
    
        int *tmp_1 = new int; 
        address_1 = tmp_1; 
        delete tmp_1; 
    
        MyClass *myC = new MyClass; 
        delete myC; 
    
        int *tmp_2 = new int; 
        address_2 = tmp_2; 
        delete tmp_2; 
    
        EXPECT_TRUE(address_1 == address_2); 
    } 
    

    我的假設是,如果有內MyClass的沒有內存泄漏和 所有聲稱內存已正確釋放,地址tmp_1和TMP_2的 應該是相同的。我只是不確定內存 分配是如何工作的。

  3. 使用插件或程序,如deleakerValgrind,但 這可能使我的代碼或測試不利大,我不知道如果 可以在上下文中使用上述反正。

謝謝!

+3

沒有任何擔保tmp_2將得到相同的地址。這是底層分配器的實現相關細節。 – galop1n

+4

http://valgrind.org/ – bosnjak

+2

'我也知道必須釋放所有已分配的資源,並且不應該有任何不明的情況'如何使用自動執行此工作的構造(如容器和智能指針)? – PaulMcKenzie

回答

0

你的第二個想法是行不通的,因爲你每次都不會得到相同的地址。

然而,你的第一個想法是一個好的開始,我會盡力在這裏改進。您可以通過調用GetProcessMemoryInfo()來自動執行該任務管理器的部分操作,而無需看任務管理器。有關如何做到這一點的信息,請參閱this answer。您想要在返回的數據結構中查看的值是PrivateUsage。如果在實例化類對象之前執行該操作,並在刪除它之後再次執行該操作,則內​​存使用情況應該相同。另外,如果你的類中的其他方法執行任何內存分配,你也可以在那裏調用它們。通過這種方式,您的測試案例可以讓您的班級在沒有任何人爲干預的情況下進行良好的鍛鍊,並且如果它檢測到內存使用量在上升,您可以隨心所欲地做任何事情(記錄內容,發出警報,無論如何)。

事情是這樣的:

// Get the starting memory usage 
int baseline = GetMemoryUsage(); // This is the function that calls GetProcessMemoryInfo() as described in the link above 

MyClass *myC = new MyClass; 
int memUsage = GetMemoryUsage(); 
myC->DoStuff(); 
if (GetMemoryUsage() != memUsage) 
    Alert("Detected memory leak in MyClass::DoStuff()"); 
memUsage = GetMemoryUsage(); 
myC->DoMoreStuff(); 
if (GetMemoryUsage() != memUsage) 
    Alert("Detected memory leak in MyClass::DoMoreStuff()"); 
// ... 
// etc - call each method that does any kind of memory allocation 
// ... 
delete myC; 
if (GetMemoryUsage() != baseline) 
    Alert("Detected memory leak in MyClass"); 


爲了實現上面提到的GetMemoryUsage()函數,你可以做這樣的事情(我沒有在我面前的一個編譯器,現在,所以請原諒任何錯別字):

#include <windows.h> 
#include <psapi.h> 
#pragma comment(lib, "psapi.lib") 

int GetMemoryUsage(); 
{ 
    PROCESS_MEMORY_COUNTERS_EX pmc; 

    DWORD processId = GetCurrentProcessId(); 
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | 
            PROCESS_VM_READ, 
            FALSE, processID); 
    if (hProcess == NULL) 
     return -1; 

    if (GetProcessMemoryInfo(hProcess, (PROCESS_MEMORY_COUNTERS *) &pmc, sizeof(pmc))) 
    { 
     CloseHandle(hProcess); 
     return pmc.PrivateUsage; 
    } 

    CloseHandle(hProcess); 
    return -1; 
} 
+0

我會試一試,並會讓你知道它是否適合我。我在哪裏可以找到GetMemoryUsage()?它不在您使用的語法的Psapi.h中。其他函數像GetProcessMemoryInfo()需要一個我沒有的進程句柄,因爲我不知道MyClass中運行的所有線程。 – hANI

+0

您需要基於我在答案中給出的鏈接來實現GetMemoryUsage()。您將從OpenProcess()獲得一個流程句柄,如代碼示例中所示。線程在這裏並不重要 - 你正在獲得流程信息 –

+0

我已經編輯了答案,爲您提供GetMemoryUsage()的示例實現() –

0

看起來像你正在尋找的是實用程序valgrind它提供了有關如何管理和釋放你的程序內存的重要信息。

瞧瞧吧valgrind.org

4

@ galop1n是正確的,無論這是你如何在一般處理泄漏。

但您確實觸及了一個有效的點,即DLL內存管理。您看到DLL中的對象需要以不同方式處理內存。你將一個內存管理委託給你的庫。在你的庫中,內存將按照它們定義的順序進行分配。他們將提供釋放該內存的方法(例如從CUDA Libraries)。

你應該在對象的構造函數和析構函數中處理你的內存。 C++標準提供了一些很棒的機制來處理你的記憶。unique_ptrshared_ptr就是一個很好的例子,在C++11中,您也可以使用std中的容器作爲相同的結果。

Valgrind也是一個偉大的工具,一旦你已經做了一切已經提到。一旦你使用了C++提供的所有可能的工具,那麼現在是時候用這個真棒工具仔細檢查你的內存使用情況了。

2

如果你使用VC++,VLD很不錯,小創造奇蹟。