0
点赞
收藏
分享

微信扫一扫

C++ 内存基本构件new [] /delete []的意义、内存泄漏原因、VC下cookie的基本布局


目录

  • ​​一、对new [] delete [] 的理解​​
  • ​​1、delete的[]遗漏会带来什么影响​​
  • ​​二、以示例探讨​​
  • ​​三、cookie的理解​​

一、对new [] delete [] 的理解

new的对象是个array类型的。

Complex* pca = new Complex[3];
//唤起三次ctor
//无法借由参数给予初值
...
delete[] pca; //唤起3次dtor

如下图,new出来的是一个array,大小为3.
new的时候要调用3次ctor,delete的时候需要调用3次dtor。分配一个array的时候,会顺带分配一个cookie,用来记录信息,最主要的就是array的长度了。
C++ 内存基本构件new [] /delete []的意义、内存泄漏原因、VC下cookie的基本布局_内存管理

1、delete的[]遗漏会带来什么影响

如果delete后面不加[],编译器会以为只需要delete所指的对象,所以只会调用一次dtor,然而cookie记录中的array长度并没有改变,此时就会少还一些内存给操作系统,从而导致内存泄漏。
str1、str2、str3会被完整回收,但是在回收之前需要调用析构函数。由于string在构造上会带有一个指针,指针指向真正的字符串的内存空间。调用三次dtor,会被很干净地清掉。而少加了[],会就只调用一次dtor,导致三块只释放掉了一块
注意泄露的内存不是str1 2 3,而是指向的真正的字符串的内存空间。
C++ 内存基本构件new [] /delete []的意义、内存泄漏原因、VC下cookie的基本布局_c++_02
**如果这里的array里面的元素类型是复数Complex,就不会造成内存泄漏,因为复数里面不包含指针。所以调用三次和调用一次也就无所谓了。**不过为了统一,还是要加上[]。

二、以示例探讨

示例代码:
A有一个默认构造函数,因为我们在new一个数组的时候不能一一地给定值,我们new是时候会调用三次构造函数。
构造函数和析构函数会在屏幕上输出占用内存位置

class A
{
public:
int id;

A() : id(0) { cout << "default ctor. this=" << this << " id=" << id << endl; }
A(int i) : id(i) { cout << "ctor. this=" << this << " id=" << id << endl; }
~A() { cout << "dtor. this=" << this << " id=" << id << endl; }
};

A* buf = new A[size]; //default ctor 3 次. [0]先於[1]先於[2])
//A必須有 default ctor, 否則 [Error] no matching function for call to 'jj02::A::A()'
A* tmp = buf;

cout << "buf=" << buf << " tmp=" << tmp << endl;

for(int i = 0; i < size; ++i)
new (tmp++) A(i); //3次 ctor

cout << "buf=" << buf << " tmp=" << tmp << endl;

delete [] buf; //dtor three times (次序逆反, [2]先於[1]先於[0])

执行结果:
1、默认构造函数,默认id= 0 ;
2、this指针会自动移动,间距是一个对象的大小(int 4个字节)
3、移动指针,设初值,调用有参构造函数
4、需要注意这样的语法​​​new(指针,指向已经分配的内存,我们在指针所指的地方进行设置初值) A(i)​​​,这属于placement new 的用法,之后的笔记会详细讲到。
5、循环过后id被修改,地址没有被修改
6、最后delete[],观察可知,调用了3次析构函数,析构的次序与构造的次序相反。(不同的编译环境析构次序可能不同)
C++ 内存基本构件new [] /delete []的意义、内存泄漏原因、VC下cookie的基本布局_内存管理_03

三、cookie的理解

在做内存管理的时候,会有一个很大的诉求,就是不要这个cookie,所以cookie的存在以及大小是我们需要理解度的。
下面是VC6中,观察malloc给我们的内存布局:而我们获得的值指向分配的10个int数据的起始地址*pi.可以看到,除了我们认定的需要的10个int外,malloc还会分配32bytes和4bytes(橙色部分)。另外还有上cookie和下cookie,负责记录整块的大小
另外还有一个pad区域,这是由于在VC6下,malloc分配的内存必须是16bytes的倍数,如果不是,则需要填充额外内存使之为16bytes的倍数。
注意cookie记录的分配的内存大小为60h,不过最后一个bit要被用做on or off 的状态的切换,所以为61h。(存疑,不是很理解这句话,之后再补上理解。)上下cookie的数值一样。
这里的delete加不加[]是没有影响的。
C++ 内存基本构件new [] /delete []的意义、内存泄漏原因、VC下cookie的基本布局_内存管理_04
如果这里我们不是存放的int类型的数据,而是放的是一个对象,并且它的析构函数是有意义的,此时编译器创造array的方式会有所不同。
注意每个demo对象中存放的是三个int,我们new了3个demo,分配的内存与之前相比多了一个3,即3个demo。
delete不加[],编译器将p当做普通指针,指向一块对象,然后以一块对象的方式去解释布局,但是此刻的布局与之前不同,多了一个3,所以解释会发生错误。
使用array new和array delete时,内存块分配是不一样的。array元素个数被写到内存块里去了。
60h内存计算方式:
60h = 32(debugger header) + 4(3:元素个数,int类型,4个bytes) + 3 x 12 (3个 demo object) + 4 (no man land) +12(pad) + 4 x 2(上喜下两个cookie)= 96个byte = 60h个byte(pad是会变动的)

C++ 内存基本构件new [] /delete []的意义、内存泄漏原因、VC下cookie的基本布局_指针_05


举报

相关推荐

0 条评论