以前在看C++书和上C++课的时候可以看到
delete[] pointer;
的用法,而大多数对于这个用法没有具体的解释,多是看到:
有一个delete运算符的特殊语法,可以释放动态分配的数组内存:
delete[] p_numbers;
方括号告诉编译器,指针指向了一个数组,而不是单个值。
引文自: 《C++程序设计:现代方法》 ,14.2 指针和数组
也没有说明如果缺少 []
会带来的后果,猜想是内存泄露,但是不明就里,于是给我来带了C++内存管理诡谲的印象。不过最近侯捷先生的讲解却很是清晰。
首先说的是构造,以Complex类为例:
Complex *c = new Complex(1,2);
执行过程为:
Complex *c; void* mem = operator new( sizeof(Complex) ); //内部调用malloc(n),分配内存 c = static_cast<Complex*>(mem); //类型转换 c->Complex::Complex(1,2); //→Complex::Complex(c,1,2),构造函数
那么在内存中执行的时候分配内存为:
红色部分为操作系统分配之Cookie,蓝色部分为填充位,目的是为了让整个长度为16的倍数。灰色区域内数据仅在Debug模式下出现,绿色区域为对象所占长度。可计算,Debug模式下的Complex实例长度为:
8[两个双精度浮点实数] + (32+4)[调试模式] + (4×2)[Cookie] → 52 + 12[填充] → 40H
那么此时向操作系统取内存时Cookie末位置1,即Cookie为 00000041
,释放时末位置0。之所以保持16(10H)的倍数即如此。
Release下的String类型长度则为:
4[指针] + (4×2)[Cookie] → 12 + 4[填充] → 10H
执行
String *s = new String(1,2); … delete s;
到 delete s
的时候会:
String::~String(s); //析构函数 operator delete(s); //释放内存,其内部调用free(s)
即执行String类析构函数后释放内存,释放Cookie标记段。看起来似乎没什么问题。
看一下
Complex *c = new Complex [3];
和
String *s = new String [3];
的内存结构,可以发现是这样的:
在顶部多存储了一个数组长度。那么执行 delete
和 delete[]
有什么区别呢?是这样的:
可以看到,对于内存而言, delete
一定会将Cookie标记段给释放掉,如果是类似Complex的数组,那么使用 delete
与 delete[]
的效果是一致的,但是针对String这类含指针类型的数组,使用 delete
仅执行首次析构,也就是在这里出现了内存泄漏。
最近怎么关心内存泄漏了?
程序跑了一晚上泄漏了8G内存,不关心一下怎么得了。