跟着侯捷老师学C++☛new动态分配内存大小篇

287 阅读2分钟

跟着侯捷老师冲啊!

new 和 delete编译

new被编译成什么

Complex* pc = new Complex(1,2)

new:先分配memory,再调用ctor

编译器转化为:

  1. void* mem = operator new( sizeof(Complex) );
    分配内存,其内部调用了malloc(n) 来分配内存
  2. pc = static_cast<Complex*>(mem);
    转型
  3. pc->Complex::Complex(1,2);
    构造函数 -> Complex::Complex(pc,1,2)

delete被编译成什么

Complex* pc = new Complex(1,2);
...
delete pc;

delete:先調用dtor,再释放内存

编译器转化为:

  1. Complex::~Complex(pc);
    调用析构函数
  2. operator delete(pc);
    释放內存。内部调用 free(pc)

动态分配内存大小

动态分配一个Complex或者String

image.png

上图每一格是4字节

Complex大小:

  1. 最左图是调试模式下的复数内存大小,左2是非调试模式下的内存。多出的调试内存是灰色块,可以看到,调试模式下多了8*4 + 4 = 36字节大小
  2. 上下各带了4字节的cookie,总共4*2 = 8 字节,作用是用来,红色
  3. Complex本身大小是8字节(re和im两个double),浅绿色。

所以最左侧,大小为 8 + (32+4) + (4*2) = 52。在VC编译器下,内存大小按16倍数分配,所以往上取16的倍数,就是64,也就是图中深绿色部分 左2,去掉调试模式下字节数,正好8 + (4*2) = 16,16倍数,不需要padding部分

cookie字节作用

调试模式下Complex大小为64字节,换算成16进制是40。然后,最后一位bit来表示是分配内存还是回收内存。对程序来说,此时是获得了一块新内存,所以是1。加上之前的40,也就是41。所以cookie字节内容为00000041

动态分配数组内存大小

image.png

Complex[3]大小:

  • 3个Complex:8*3
  • 调试模式:32+4
  • cookie:4*2
  • 多一个整数记录数组的个数,图中白色部分;整数大小为4

为何需要delete[]

String* p = new String[3];
...
delete[] p; //唤起3次dtor
String* p = new String[3];
...
delete p; //唤起1次dtor

不管是delete还是delete[],都不影响下面的整块内存删除。因为这一整块的大小由cookie记录的,只要cookie正确,这一块内存就能正确删除,不会内存泄漏。 image.png

但只有写delete[],编译器才知道要删除的是数组,所以才会去调用3次析构函数,不然就只会执行一次析构函数,回收掉这一个object里的动态内存。但其余的两个object,它们中的动态内存就会一直留着,变成内存泄露

image.png

这里也可以看出来,如果class里面没有指针,这里使用 delete 而不是 delete[] 也不会造成内存泄漏。因为根本不用调用析构函数来处理动态内存(当然这是不推荐的!按照规范写!)