2010-06-16 87 views
1

我得到了下面一段代碼,我已經縮小了內存泄漏的範圍(即,在任務管理器中,專用工作集的內存隨着相同的重複輸入而增加串)。我理解堆和棧內存的概念,以及爲避免內存泄漏的一般規則,但一些地方仍然會錯誤:在C++中識別內存泄漏

while(!quit){ 
    char* thebuffer = new char[210]; 
    //checked the function, it isn't creating the leak 
    int size = FuncToObtainInputTextFromApp(thebuffer); //stored in thebuffer 
    string bufferstring = thebuffer; 
    int startlog = bufferstring.find("$"); 
    int endlog = bufferstring.find("&"); 
    string str_text=""; 
    str_text = bufferstring.substr(startlog,endlog-startlog+1); 
    String^ str_text_m = gcnew String(str_text_m.c_str()); 
    //some work done 
    delete str_text_m; 
    delete [] thebuffer; 
} 

我能想到的唯一的事情是它可能是創造'string str_text',因爲它從來沒有超出範圍,因爲它只是在這段時間重新開放?如果是這樣,我將如何解決?在while循環之外定義它並不能解決它,因爲它也會保留在範圍之內。任何幫助將不勝感激。

+2

這不是C++,也就是C++/CLI。而在那個奇怪的混合。 – GManNickG 2010-06-16 20:27:03

+2

這實際上是否會崩潰,最終呢?當你使用垃圾收集時,它可能只是使用可用內存來避免gc掃描。 – 2010-06-16 20:30:06

+0

我不知道它是什麼,但它不是'string str_text',它存在於堆棧中,因此您不必擔心刪除它。 – 2010-06-16 20:30:39

回答

4

應該使用範圍限制的資源管理(也被稱爲RAII),這是在任何情況下很好的做法。切勿手動分配內存,將其保存在自動分配的類中,以便在析構函數中爲您清理資源。

您的代碼可能是:

while(!quit) 
{ 
    // completely safe, no leaks possible 
    std::vector<char> thebuffer(210); 
    int size = FuncToObtainInputTextFromApp(&thebuffer[0]); 

    // you never used size, this should be better 
    string bufferstring(thebuffer, size); 

    // find does not return an int, but a size_t 
    std::size_t startlog = bufferstring.find("$"); 
    std::size_t endlog = bufferstring.find("&"); 

    // why was this split across two lines? 
    // there's also no checks to ensure the above find 
    // calls worked, be careful 
    string str_text = bufferstring.substr(startlog, endlog - startlog + 1); 

    // why copy the string into a String? why not construct 
    // this directly? 
    String^ str_text_m = gcnew String(str_text_m.c_str()); 

    // ... 

    // don't really need to do that, I think, 
    // it's garbage collected for a reason 
    // delete str_text_m; 
} 

的一點是,如果你確保你的資源是由自己釋放你不會得到內存泄漏。也許垃圾收集器正在導致您的泄漏檢測器誤點火。

在附註中,您的代碼似乎有很多不必要的複製,您可能需要重新考慮複製字符串的次數。 (例如,查找"$""&",而它在載體中,並從那裏只是複製到str_text,不需要中間副本。)

+0

我唯一的一點是未經檢查的緩衝區使用情況 - 但除此之外。 – Lee 2010-06-16 20:52:23

+0

@李:你什麼意思? – GManNickG 2010-06-16 20:53:30

+0

那麼這也是原始代碼中的一個問題 - 如果FuncToObtainInputTextFromApp()放入緩衝區的數據量大於210,那麼它會溢出。但是,在他的情況下,它將在堆上,因此不太可能在可執行區域。而上面的緩衝區將會在堆棧上。或者我錯了? – Lee 2010-06-16 21:05:01

1

我知道它的建議是在刪除它之後將釋放的變量設置爲NULL,以防止任何無效的內存引用。可能有幫助,可能不會。

delete [] thebuffer; 
thebuffer = NULL;  // Clear a to prevent using invalid memory reference 
2

你#使用STD,使str_text的類型的std :: string?也許你打算寫 -

String^ str_text_m = gcnew String(str_text.c_str()); 

(而不是gcnew字符串(str_text_m.c_str()))?

最重要的是,用gcnew分配一個String(或任何對象)是聲明你將而不是明確地刪除它 - 你把它留給垃圾收集器。不知道會發生什麼,如果你刪除它(技術上它甚至不是一個指針,絕對不會引用CRT堆上的任何東西,新的/刪除的權力)。

您可以安全地評論str_text_m的刪除。你可以期望在一些時間間隔內逐漸增加內存(gcnew的積累處)和突然減少(垃圾回收處)。

更妙的是,你也許可以重複使用str_text_m,沿着線 -

String^ str_text_m = gcnew String(); 
    while(!quit){ 
     ... 
     str_text_m = String(str_text.c_str()); 
     ... 
    } 
0

有一個叫做DevPartner工具,可以在運行時捕獲所有的內存泄漏。如果您的應用程序具有pdb,則會在您的應用程序中爲您提供所有內存泄漏已被遵守的行號。

這是最適用於真正的大型應用程序。