转自:http://blog.csdn.net/cctt_1/archive/2010/07/22/5755632.aspx
相信几乎每个人都遇到过memory leak的问题。解决方法各不相同。
1。防止内存泄露
例如c++中使用auto_ptr, java中自己的垃圾回收。对于纯java, python的语言编写的东西,memory leak一般不是啥米的问题,这些语言最严重的问题是内存不足。这些java要处理内存不足就-Xmx1024m或者开更大的内存,或者闲得无聊的时候调调gc. python的解决方法差不多,不过它可以显式delete. 另外听说python调用django时会有内存分配不足的问题,原因在于django这鬼东西在debug==true时没有对sql查询进行释放。下面接着过去的话题扯下c++/c这些需要自己care的语言。 c++中有auto_ptr这东东算是可以,因为遵循RAII(resource acquirement is initial 不知道自己英文拼对了没有), 也就是说:在类初始化的时候申请资源,在类析构的时候释放资源。另外注意析构函数是virtual的。为啥米呢?因为要多态调用析构父类。如果自己写的类不是那么标准,喜欢到处申请资源,到处释放资源,还是建议使用auto_ptr这个类,它在<memory>中。其实auto_ptr类似于下面的代码:
这东东的作用在于简化下面的代码:
可以说还是有些用处的..不过不能用于申请数组...除非你想申请auto_ptr的数组。另外传说不能用于容器类。所以为了不让内存泄露,还是需要谨慎小心。
2。监测内存泄露,使用监测内存泄露的小工具
另外有一些监测工具可以帮你检查一部分内存泄露的问题。有些工具其实就是替换了free/malloc/realloc/calloc 或者是 new/delete.采用宏定义就可以轻松做到:
然后就可以截获new/delete的函数调用,至于你想再多做一些事情,就看你宏定义和你函数的具体写法了。然后就如同左右括号匹配一样。当然往往不是那么简单,例如类中的一些指针有还有一些内存检测是需要你传入指针进去,然后catch指针做些监测工作。
但有些memory leak的问题很难被监测到,或者有时候会被误报。比如某个指针在函数中申请空间并传出,然后在外面进行n次转换,并进行加加见见运算,最后变为另外一个指针。除非检测工具做了名字的转换,可以进行数学运算,比如int * a = new int[20]; int * c = ++a; delete [] --c;当然这里只是一个模拟,没有人会这样写代码。但是真正的程序中很有可能代码简化后就是这样的情况。当然进行dynamic_cast的情况更加复杂,还需要判断析构函数是否是虚函数等问题。
3。断言法
测试程序正确性很难监测出内存泄露的情况。
下面以链表为例:list_insert()时原List比现List少1个元素,list_delete()时,原List比现List多一个元素。
即使这里的size变化是正确的,这也依旧不能保证list_delete()中调用了合适的delete 方法,有可能没有进行delete, 或者进行了节点的delete,但是组成链表中的节点的析构函数没有写好,也会造成内存泄露。个人就遇到PG中删除链表函数的问题。原链表长度的确是减小了。但是链表节点的内存的确没有释放。
4。模拟法
这个方法其实很好用,一般在已经确定可能是某一个大模块的问题,但是不清楚内部可能的路径,也有可能是路径太过复杂。这里就可以模拟一下。化简各种流程,仅仅调用申请释放资源的几个主要函数。然后逐一排除各个主要函数的可能性。例如那个链表,如果起初的业务流程有许多复杂的链表操作,但是申请释放空间的地方其实就是list_insert()和list_delete(),这就可以仅仅是调用几千次list_new(),list_delete()看看情况.内存泄露就会明显显现。