自强不息,厚德载物。
分类: C/C++
2015-06-29 23:39:25
一,引言
内存泄漏是C/C++成员的梦寐,指不定就在哪个代码中就出现了。对于C/C++程序员来说,上一次程序内存泄漏的场景一定还历历在目,也许你现在正在运行的代码就会有内存泄漏,只是你没有发现而已。那么怎样能防止内存泄漏呢?我想除了不动态申请内存或者是使用像Java,C#这种自管理内存的语言,否则,谁也不敢拍着胸膛说,老子写的代码就没有内存泄漏。但是我们是有方法减少内存泄漏。
二,场景
这还有说吗?谁都知道肯定是某个地方使用了new或者malloc, 而没有调用delete或者free来释放。 这个是最基本知识, 也是最所有内存泄漏的原因, 但是一般内存泄漏都是指热门代码执行过程的内存泄漏,就是在短时间内反复调用, 或者周期性调用的代码,这中地方的内存泄漏能立马吃光系统内存,至于,冷门代码的内存泄漏可以暂缓,比如整个程序的生命周期中只运行一次,而在这一次中泄漏了几个字节,对于应用程序来说,起不到决定性的作用。
在我们的代码中有经常会有动态申请一个内存缓冲区,典型的就是结构体,类等,使用临时的缓冲区存储数据, 进行计算, 完成之后, 释放内存。其代码一般如下:
Void fun1()
{
// 为了篇幅,代码格式不一定正确
struct A* a = (struct A*)malloc(sizeof(A));
// do something
free(a);a = null;
}
三,目标
能不能在编译的时候就能发现上面场景的内存泄漏,有人就会说, 别和开玩笑,要是编译能解决内存泄漏问题,C/C++程序会失业的。我们就以此为目标, 看看能不能解决。
四,Solution
看到上面的这种场景,对于变量a,其生命周期也就是从申请内存到释放内存,如果在申请内存之前使用会编译错误,释放之后使用,coredump是最幸运的了。是不是想到Java或者C#常用的Guard方法, 或者是其关键字using的作用呢?如果一个C/C++程序员要向Java或者C#学习,难免有些讽刺意味,但是他们确实有很多很好解决方案是值得我们学习的,且看看java的Using的使用方法:
using(AClass a = new AClass())
{
// do something for a
}
在using的两个大括号之外都是不能使用变量a, 我们是不是也可以是用类似的一些技术来使得1. 如果使用了new或者malloc就必须使用delete或者free,缺少就会编译错误。2. 在这之外使用我们这个变量都会编译错误。当然是可以的,我们可以利用宏+do while来解决这个问题。看看下面这两个宏, 然后我们来分析这个两个宏为什么可以解决我们上面提到的目标。
#define MEMORY_GUARD_BEGIN(type, variable) \
do{ type* variable = (type*)malloc(sizeof(type))
#define MEMORY_GUARD_END(variable) \
free(variable); variable =NULL;}while(0)
看到这两个宏之后想想,对于我们第一个问题,由于有do..while的存在,只要这两个宏有一个不在同一个函数,都会编译出错, 第二个问题,由于变量的定义是在do..while中,在这之外使用都会编译出错,会报为定义的变量错误。当然在程序中还可以使用其变化方式来避免内存泄漏。
五, 弊端
主要弊端就是不能跨函数。不能在两个宏之间将变量释放了,当然可以写一个判断。