Memory Leak 攻略

相信几乎每个人都遇到过memory leak的问题。解决方法各不相同。

1。防止内存泄露

例如c中使用auto_ptr, java中自己的垃圾回收。对于纯java, python的语言编写的东西,memory
leak一般不是啥米的问题,这些语言最严重的问题是内存不足。这些java要处理内存不足就-Xmx1024m或者开更大的内存,或者闲得无聊的时候调调gc.
python的解决方法差不多,不过它可以显式delete. 另外听说python调用django时会有内存分配不足的问题,原因在于django这鬼东西在de
bug==true时没有对sql查询进行释放。下面接着过去的话题扯下c
/c这些需要自己care的语言。
c++中有auto_ptr这东东算是可以,因为遵循RAII(resource acquirement is initial 不知道自己英文拼对了没有), 也
就是说:在类初始化的时候申请资源,在类析构的时候释放资源。另外注意析构函数是virtual的。为啥米呢?因为要多态调用析构父类。如果自己写的类不是那么标准,
喜欢到处申请资源,到处释放资源,还是建议使用auto_ptr这个类,它在中。其实auto_ptr类似于下面的代码:

template class simple_auto_ptr{ private: T* point; public: explicit
simple_auto_ptr(T* point):point(point){} virtual ~simple_auto_ptr(){delete
point;} }; 调用代码例如simple_auto_ptr a(new int(3));

这东东的作用在于简化下面的代码:

void foo(){ T* a = new T(); try{ throw something; }catch(something){
if(NULL!=a){ delete a; a=NULL; } } if(NULL != a) delete a; } 使用auto_ptr
将上面的简化为 void foo(){ auto_ptr a(new T()); throw something; }

可以说还是有些用处的…不过不能用于申请数组…除非你想申请auto_ptr的数组。另外传说不能用于容器类。所以为了不让内存泄露,还是需要谨慎小心。

2。监测内存泄露,使用监测内存泄露的小工具

另外有一些监测工具可以帮你检查一部分内存泄露的问题。有些工具其实就是替换了free/malloc/realloc/calloc 或者是
new/delete.采用宏定义就可以轻松做到:

#define new MY_NEW #define MY_NEW my_new

然后就可以截获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多一个元素。

List * l = new List(); size_t old = l->size(); l->list_insert(some elements);
size_t new = l->size(); assert(new-old == 1); old = l->size();
l->list_delete(some elements); new = l->size(); assert(old-new == 1); //
另外必须保证list的size其实和具体的值无关,应该是遍历后的结果

即使这里的size变化是正确的,这也依旧不能保证list_delete()中调用了合适的delete 方法,有可能没有进行delete, 或者进行了节点的d
elete,但是组成链表中的节点的析构函数没有写好,也会造成内存泄露。个人就遇到PG中删除链表函数的问题。原链表长度的确是减小了。但是链表节点的内存的确没有
释放。

4。模拟法

这个方法其实很好用,一般在已经确定可能是某一个大模块的问题,但是不清楚内部可能的路径,也有可能是路径太过复杂。这里就可以模拟一下。化简各种流程,仅仅调用申请
释放资源的几个主要函数。然后逐一排除各个主要函数的可能性。例如那个链表,如果起初的业务流程有许多复杂的链表操作,但是申请释放空间的地方其实就是list_in
sert()和list_delete(),这就可以仅仅是调用几千次list_new(),list_delete()看看情况.内存泄露就会明显显现。