前言
在C++的开发过程中,我们经常会用到new一个对象数组,然后使用delete[] 进行内存的释放,那对于背后的原理我们是否理解了呢?而本文是简单分享了下藏匿在背后的一些原理
实例分析
下面来看下,以下一行代码的内存分配
String* p = new String[3];
上述的示例代码非常简单,通过new创建3个String对象,这条语句背后的内存分配如下如所示:
如上图所示,
上下各4个字节的存储空间的数据都是21h, 在C++中被称作Cookie
21h其中20h(16进制)表示如果上图所示的结构所分配的内存大小-32字节,怎么计算的呢?
对于String类型了解的话,就能知道String类型实质上是包含一个指针类型,也就是创建对象后,数据部分只需要占用4个字节的内存空间,而图示中的“3”表示是有3个String对象,而“3”所占用的内存空间为4个字节,所以当前内存空间为: 43(3个String对象) + 42(Cookie) + 4(“3”所占用的空间) = 24. 那这样算出来不是24字节吗? 怎么是32字节呢?实质上呢编译器要求是16字节对齐所以需要+8字节对齐,也就是图示中的pad区域.
然后delete操作时?背后又发生了什么呢?
String* p = new String[3];
...
delete[] p; //调用3次析构函数
在之前的这篇文章【C & C++】C++堆栈与内存管理有分享过,delete 实质上做了两件事情:
- 先调用析构函数
- 在释放p所分配的内存空间
而在上述例子中,调用delete 进行p的内存释放时,加上了"[]"目的是为了告诉编译器,"你"在释放的是对象数组,然后编译在背后会调换用三次析构函数,在析构函数中进行每一个对象中的指针变量所指的内存空间然后在释放p本身所指的内存空间
然代码如下实现,
String* p = new String[3];
...
deletep; //调用1次析构函数
则会导致,只调用一次析构函数,这样会导致的问题是,可能只有第一对象中的指针变量所指的动态内存地址被释放,而出现内存泄露. 这里需要强调的是: 指针变量p所指向的内存不会出现内存泄露的情况,在调换用析构函数后会进行p的释放.
如下图所示,