梁 兄

QQ: 160216918 QQ群: 26678700 MSN: lb_bing@hotmail.com

  C++博客 :: 首页 :: 联系 :: 聚合  :: 管理
  53 Posts :: 5 Stories :: 358 Comments :: 0 Trackbacks

5. 内存分配malloc/new和释放free/delete的调用点不在一个代码层次上,引起内存泄露:
  已有代码:
    int miGetHttpContent( void * apHttpContext, char ** apsContent ) {
      int liNextLen = 16384; // 16 kb
      int liTotalLen = 0;
      char * lsBuff = (char*)malloc( liNextLen );
      
      ......// 通过libxml2提供的接口获取http body的内容, 具体处理不重要
      
      *apsContent = lsBuff;
      return liTotalLen;
    } 
    
    调用代码:
     具体代码不再提供,就是没有调用:
      if( NULL != *apsContent ) {
        free( *apsContent );
        *apsContent = NULL;
      }
     
   问题分析:
            地球人都知道,没有调用free()就产生内存泄漏了。大家可能会说,那是调用者
   的问题,谁叫他粗心大意,又不用purify等测试内存泄漏的工具来测试。如果写函数
   的人把函数功能说明、参数意义、返回值情况都写清楚了,上层使用这个函数的人
   自己不看说明,主要责任确实在上层开发人员。

             但我要说的是,内存分配malloc/new和释放free/delete的调用点不在一个
   代码层次上的做法,确实容易使人产生错误,一不小心就忘记调用free/delete了。
   因为需要调用free/delete来释放内存的人,常常不是写malloc/new来分配内存的人,
   就是底层开发人员和上层开发人员不是一个人,那么这种情况下很容易产生错误。

              所以,不是必须要动态分配内存的时候,我们尽量不要调用malloc/new来从heap上
   获取内存;如果必须要动态分配内存,那么尽量把malloc/new调用和free/delete
   放到一个层次上,别搞这种工具函数里分配,然后在外层/上层要别人去释放;如果
   必须要动态分配内存,同时还必须要在不同层次上的话,那你写对malloc/new调用
   的函数的人,请把你的函数说明写的尽量清楚!不要让别人老去看你的代码,以发现
   里面是否有malloc/new调用,不管项目工期怎么紧张。

     现在有部分C++程序员,好象并不懂new一个对象,到底那些东西是占用了heap上
   的内存,调用new和不调用new在内存上的真实区别在哪里。例如:
     class clsTest {
      public:
        clsTest( );
        ~clsTest( );
        
       private:
         char * cpcStr;
     };
     
     clsTest::clsTest()
     {
       cpcStr = new char[ 1024 ];
     }
     
     clsTest::~clsTest()
     {
       if( NULL != cpcStr ) {
         delete[] cpcStr;
       }
     }
     
     // 调用一:
     clsTest lpoTest = new clsTest();
     delete lpoTest;
     
     // 调用二:
     clsTest loTest;
     
                现在我们程序里“调用一”方式出现很多,曾经问了开发人员,解释是因为怕使用太多stack上内存, 怕stack涨破,因为unix对进程确实有限制,用ulimit命令可以查看。我们细细想想,到底创建一个
     clsTest对象,那些需要分配内存,其实就是成员数据char * cpcStr,这里有两个方面:一个是这个
     指针本身,是一个32位整型,4字节;另一个就是构造函数里调用new分配的1k字节。
     那么不管那种调用方式,构造函数里调用new分配的1k字节,一定是从heap上获取的;从而可以看出,
     上面两种调用,指针本身4字节,是从heap分配的,还是从stack分配的,这个区别。

               那么就这指针本身4字节,我们需要担心会涨破stack吗?!如果是继承里,就算是考虑到vtbl等开销,
     和我们自己写的代码分配的内存来比较,它内部开销也是微乎其微吧。
     在没必要使用new创建对象时,我们还是不分青红皂白的去使用,带来的后果一是增大了因为疏忽而
     产生内存泄漏的机会,二是毕竟从heap分配内存没有从stack分配来的快。

              当然也有人说solaris系统内存算法很优秀,new并不慢,也很少内存碎片。就算是吧,那你非得要
    多写一行代码:delete lpoTest; 非得干这种拖裤子打屁----多此一举的事吗。

posted on 2008-03-06 13:01 梁-兄 阅读(1359) 评论(4)  编辑 收藏 引用 所属分类: C/C++项目管理

Feedback

# re: 评审公司去年项目代码发现的一些问题之二 2008-03-06 14:22 kacy16
// 调用一:
clsTest lpoTest = new clsTest();
delete lpoTest;

这段代码是否有点问题,应该改为 clsTest *lpoTest=new clsTest()?
  回复  更多评论
  

# re: 评审公司去年项目代码发现的一些问题之二 2008-03-06 14:32 梁-兄
呃, 这位兄弟很细心, 我写错了!
十分感谢这么细心地阅读!  回复  更多评论
  

# re: 评审公司去年项目代码发现的一些问题之二 2008-03-06 16:08 很好
这个的确不应该new的。
拖裤子打(-->放)屁----多此一举
  回复  更多评论
  

# re: 评审公司去年项目代码发现的一些问题之二 2008-03-07 09:14 Robertxiao
看了这篇文章让我对new的用法会更加谨慎了,确实C++/C在用new管理堆这一块出现的问题很多,我们往往防不胜防.解决方式一:是尽量审慎的眼光来看是否要在堆上分配呢?如果分配不在一个地方,或是虽是在同一个地方,但其间出现了错误而又对这个错误进行了外围的catch了.二:对于不在同一个地方成对使用分配与释放应明的写出调用者应负责做的事.  回复  更多评论