2010-06-16 88 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,则会在您的应用程序中为您提供所有内存泄漏已被遵守的行号。

这是最适用于真正的大型应用程序。