是否有内存泄漏,我正确释放内存

时间:2011-01-10 15:28:06

标签: c++ memory-leaks

亲爱的会员,  我是否在正确的位置释放内存让我感到困惑。 特别是* sResult?

int ReadToSerialPort( char *psResponse, int iMax)  
{  

    size_t iIn;  

    if ( fd < 1 )  
    {  
        printf( "port is not open\n" );  
        return -1;  
    }       

    iIn = read( fd, psResponse, iMax-1 );     
    if ( iIn < 0 )      
    {
        if ( errno == EAGAIN )  
        {  
            printf( "The errror in READ" );  
            return 0; // assume that command generated no response      
        }  
        else  
            printf( "read error %d %s\n", errno, strerror(errno) );  

   }  
   else   
 psResponse[(int)iIn<(int)iMax?iIn:iMax] = '\n';   

  return iIn;   

} // end ReadAdrPort  
int MultiQuery ()  
{  
    // check database connectivity   

 // code to check  DB

     while (1)  
     { //while start   

         // char *sResult = NULL;  
          char  *sResult = (char *)malloc(4096);   

          // Reading from H/W  
          if ( ( ReadToSerialPort(sResult,4096) ) > 0 )      
          {   

              // code to trim read line and put into db....   



            printf(" before free is %s\n", sResult);   

             free(sResult);        
             sResult = NULL;    
         } // end ifReadToSerialPort >0     

        //*sResult = NULL;    


     } // while(1) ends;      

    fclose(errorlog);  
    fclose(errorlog2);   
    mysql_close(&mysql);   
    return 0;  
}

2 个答案:

答案 0 :(得分:7)

您是否研究过检测内存泄漏的工具,例如Valgrind? (Windows substitutes

在代码上运行这些内容会向您显示您正在泄漏多少内存,很可能在哪里。

这不是一个完整的程序,所以我们无法为您传递它。一些建议:

  • 分解例程并具有单独的测试可执行文件,以便您可以确保代码中的一些内容没有内存泄漏。这有点像测试驱动开发 - 您为函数编写测试以确保它正常工作并正确验证输入,并测试它是否存在内存泄漏。
  • 像时尚一样在图书馆中发展。这应该是第二天性,因为它优化了代码重用(除非重复自己是有利的,否则不要重复自己)并帮助完成上述任务。

编辑:我会扩展它。为了让您了解内存泄漏何时发生,请考虑以下事项:

#include <iostream>

using namespace std;

int main(int argc, char** argv)
{
    int* arr = new int(5);
    // delete arr; // <-- uncomment this to fix memalloc bug.
    return 0;
}

这个程序非常简单地在堆上分配4个字节,然后退出而不整理那个内存。

Valgrind会告诉你:

HEAP SUMMARY:
==23008==     in use at exit: 4 bytes in 1 blocks
==23008==   total heap usage: 1 allocs, 0 frees, 4 bytes allocated
==23008== 
==23008== LEAK SUMMARY:
==23008==    definitely lost: 4 bytes in 1 blocks
==23008==    indirectly lost: 0 bytes in 0 blocks
==23008==      possibly lost: 0 bytes in 0 blocks
==23008==    still reachable: 0 bytes in 0 blocks
==23008==         suppressed: 0 bytes in 0 blocks

为什么呢?因为您没有delete使用new分配的内存。粗略地说,这很复杂。

我说它很复杂,因为程序很快变成大型代码库,内存泄漏突然变得更加复杂。谁分配了内存?谁释放了它?内存是作为库的一部分分配的吗?开始使用数组时会发生什么?通过释放阵列的外部级别而不是内部级别,可能会导致间接内存丢失。请参阅indirect memory loss

这很快变得非常复杂,特别是当函数开始分配内存并开始在别处使用它们时,你开始依赖于编程确定的内存大小,例如基于用户输入的字符串长度。 maxlen+1错误是常见错误,可能会在较大的2D数据阵列中造成巨大泄漏。

根据您的新问题编辑2:

首先,如果您使用的是C ++,我强烈建议您忘记malloc。使用newdelete因为它们理解多态性和对象,而malloc则不然。您的构造函数可能无法正确调用。如果您需要字符串,请使用string类型。如果您需要数组,vector通常会这样做。

其次,如果读取操作正常,则只释放内存。为什么?您仍然分配了内存,因此无论读取操作是否有效,您仍然需要释放内存。您还应检查内存是否确实已分配,否则您将因访问不应访问的内存而导致分段错误。

编辑三:

好的,根据您的评论,请考虑以下代码,我认为您提议:

char* buffer = (char*)malloc(4096*sizeof(char));

if ( ReadToSerialPort(buffer, ...) > 0 ) // you are proposing to free in this func call
{
    // do stuff A

}

// do stuff B

// free(buffer); // <-- you should free buffer here

如果你在函数调用中释放会发生什么?嗯,这实际上还不错,除了你可能会意外使用的代码范围内仍有一个变量。如果你这样做,你将访问你明确发布的内存,这可能会导致你的程序崩溃。

我假设在某个阶段你想在A部分或B部分使用这个缓冲区。在这种情况下你需要分配内存。

至于只在if语句中释放,如果read函数不起作用,这是一个保证内存泄漏,因为该内存永远不会被释放。

这是你应该怎么做的:

//
// I maintain you should use a string here, or 
// if you insist on char*, use new.
// and delete.
//
char* buffer = (char*)malloc(4096*sizeof(char)); 

if ( buffer == NULL )
{
    // os refused the alloc.
    cout << "Out of memory\n" << endl;
    return 1;
}

if ( ReadToSerialPort(buffer, ...) > 0 ) // this call frees as well?
{
    // do stuff A using buffer

}

// do stuff B using buffer

free(buffer); // <-- you should free buffer here

编辑4:只是为了澄清:

不要混用malloc / free和new / delete 。如果你是malloc,释放那个内存,如果是新的,删除那个内存。如果你正在与C代码接口,除非它需要类似int的数组,你可以使用string类型,不需要动态分配。除非您传递给C函数而无法控制,否则您应该在数组上方考虑vector。只有当你传递给C函数时,如果你需要进入C的malloc和free方法的世界,你就无法控制。

答案 1 :(得分:1)

快速使用Ctrl + F(因为你发布了太多不相关的代码),表明你分配的唯一内存是* sResult,并且在释放内存之前没有exit子句,所以是的。在略读这段代码之后,我会犹豫使用“你做得对”这句话,但你正在这样做。