登录  
 加关注
查看详情
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

秒大刀 博客

好好学习 天天向上

 
 
 

日志

 
 
 
 

内存泄漏  

2009-01-07 18:16:59|  分类: C/C++ |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

     C语言的内存分配是用malloc类函数做的,释放用的是free。如果用户忘记free malloc出的内存则就成为内存泄漏,这些泄漏的内存因不再有任何指针只有,也将永久的无法被释放,除非进程被OS结束,这是属于该进程的所有资源将被操作系统回收。但在嵌入式系统上不能保证操作系统对所有资源跟踪维护的精确性。

       到了C++时代,内存泄漏得到了一定程度的缓解。因为构造函数的加入和析构函数的加入,使得程序员可以比较轻松的去维护内存和其他系统资源。不过内存泄漏仍是一个非常严肃的问题,必须时刻谨慎面对。在大型工程中杜绝内存泄漏绝非易事。

       通常要防止内存泄漏是无银弹的,但还好有一些基本的原则可以去遵守。我就谈下我对这个问题一些粗浅的理解吧,欢迎鄙视。

 

写法上应该注意的:

       如果类成员有指针,则一定要在构造函数的初始化列表中讲其置空。这即可以防止野指针的出现,也利于在析构中不分青红皂白的delete。该原则可以扩充到将类中所有的成员在构造函数的初始化列表中给予合适的值。

       属于一个类的资源,比如内存,应该由该类负责回收,而不应该交给别人。同理,该类也没有任何理由去回收别人的资源。这可以防止资源管理混乱从而导致问题。

       一般情况下指针delete后请及时的将指针置空。这样可以防止野指针,也可以明确的告诉你这块内存已经回收,当然也就明确的非0的指针肯定是没有回收的。

       注意不要将delete[]误用为delete,这会导致内存泄漏。和这条关联的要注意不要对任何数组类型进行typedef,否则你会困惑到底该用delete[]还是delete。

       malloc的内存一定要用free,new的内存一定要用delete。不要去尝试混合使用会有什么结果,答案是不可预料。

       如果涉及到有动态资源管理的类型体系,应该考虑将非最终子类的析构函数写为virtual析构。这可以防止通过基类指针调用析构函数时漏调子类构造函数而导致的资源泄漏。

       不要在函数内部分配内存,然后返回地址,因为用户可能会再外面忘记调用delete。定长的小对象可以考虑局部static解法,或者可以通过参数将外部分配好的内存传进来。

       考虑使用成熟的容器或资源管理方案,尽量避免手工去维护资源。比如STL或者聪明指针,但嵌入式环境可能对这些东西有严格的限制。

      

工具辅助查错:

       有很多自动化的程序查错工具,扫描后可以得知代码可能的危险点,这些工具有时候可能辅助差内存泄漏、内存覆盖等问题。此类工具我用过一些,大多不是很智能,只能做到给出一个可能的建议,误报率极高,得自己去非常认真的审视,不过也确实发现了很多没有注意的bug。另外此类工具大多都是商业性质的,需要收费,这可能需要公司提供。

 

通过重载new的、delete来查错:

       自己重写new、delete,然后在程序退出的时候看看有那些内存没有回收就可以了。比如在分配的时候将通过宏将代码所在的文件和行提取出来压到hash_map中去,最后在程序退出前遍历hash_map得到所有未释放内存对应的源码位置。

 

通过内存池来查错:

       内存池其实主要是用于内存的的高速释放和回收的,同时也能在一定程度上缓解内存碎片的问题。其实内存池也可以辅助查内存泄漏。当池回收的时候池中没有被正确释放的内存即为被泄漏的内存。用一些技巧是可以得到分配这些内存的代码位置的,方法和上面重载new、delete的做法类似。

 

手工调内存泄漏

       观察内存泄漏的频率和大小,观察内存泄漏时的操作,确定可能的泄漏点。比如打开某窗口后关闭发现有内存泄漏,那可能就是该窗口某处有bug。如果泄漏值非常大,可能就是珍惜资源的泄漏,比如视频、音频、图片、大的缓冲区之类的;如果是小量的泄漏,可能就是某个变量没有释放。根据泄漏量的大小,可以尝试去推测你到底是泄漏了什么对象。

       定位了可能发生泄漏的位置和性质后,应该认真的审视代码。遵从上面提到的放内存泄漏的写法,碰到不顺眼的都改掉,即使没有找到该找到的,最起码可以防止以后其他地方再神秘的出现类似的问题。查的时候应该按照前面推测的范围一个功能类一个功能类的去看,然后一个一个的去排除,如果还没有发现就认真看是否逻辑层对这些功能类的时候上有问题。查的时候尤其要注意那些不经常执行的分支。比如某文件打开失败后的错误处理,网络链接中段后的错误处理,用处输入不正确的错误处理,抛出异常后的返回流程等。

       如果还没有找到,可以改变不同的策略,在不同的侧面去反复尝试以上两条。内存泄漏一般是不好查的,尤其是非常概率小出现的、基本上很难复现的小剂量泄漏,能稳定复现、概率比较大尺寸比较大的泄漏还是比较好查的。

 

 

       内存泄漏的查错,相对来说会比空指针之类的bug难一些。一定要有充足的信心和耐心,静静的调,bug肯定会被你抓住的。哇!六条腿的bug,我看见你了!

 

 

扩充阅读:

       对内存模型一个非常好的比喻,讲到了内存碎片与OOM:

        http://dearymz.blog.163.com/blog/static/2056574200722491917883/

       VC其实也自带了一个内存泄漏查错工具,F5启动程序执行完后会打出所有泄漏的内存:

           http://www.cppblog.com/Ipedo/archive/2005/10/27/867.aspx

       通过重载new、delete来查内存泄漏:http://dev.csdn.net/article/58/58407.shtm

       关于内存池的一个Demo和一些链接:http://dearymz.blog.163.com/blog/static/205657420081181329476/

 

 

秒大刀2008年12月15日写给杨婷

  评论这张
 
阅读(981)| 评论(0)

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018