new/delete 进一步探讨
一、new/delete 的过程
A* pa = new A(); operator new(); // 其中调用malloc来分配内存 A::A(); delete pa; A::~A(); operator delete(); // 其中调用free释放内存
new/delete(malloc/free) 释放内存时,也会做一些合并旁边空闲内存块的操作,将零散的内存块合并成更大的内存块。其内部工作很复杂。
而且分配了内存之后还会在这块内存附近记录分配的内存大小,在delete的时候,只是传入要释放的内存块首地址,内存的大小信息存放在这块内存块周围
new一个对象主要会分配哪些内存:
char* p = new char[10]; 1、记录分配了多少个字节的数字(4字节) 2、Debug模式下可能会有一些调试信息,占用一些字节(30-60字节) 3、分配出去的内存(10字节)(返回的指针地址为该段内存的地址)
注意:如果是对象数组,还会在这块内存前,分配一个4字节的内存,用来记录数组的元素个数,执行几次构造和析构,都是通过这个数字来记录的
4、其他一些必要的信息,一些为提高效率进行边界调整的字节填充(十—几十字节) 5、尾信息,用于回收内存时当作内存尾标记(4字节)
分配一块内存还会附加一些其他的内存,所以频繁的分配小块内存,则很浪费
二、重载 operator new/delete 和 operator new[]/delete[]
class A { public: static void* operator new(size_t size); // size分配的内存大小 static void operator delete(void* pa); static void* operator new[](size_t size); // size分配的内存大小 static void operator delete[](void* pa); }; void* A::operator new(size_t size) // 这个size是系统根据类的大小指定的 { // 下面是必须要做的事情,也是系统默认做的事情 // 不分配内存会报错 A* pa = (A*)malloc(size); return pa; } void A::operator delete(void* pa) { free(pa); } void* A::operator new[](size_t size) // 这个size = 所有类的大小之后 + 4字节(用于存储数组个数) { // malloc 分配的内存包括储存数组个数的数字,但是分配到用户手中的不包含这个数字的内存 // 比如空类大小为1,这时候size传入的是7,但是分配到用户手中的大小还是3 A* pa = (A*)malloc(size); return pa; } void A::operator delete[](void* pa) { free(pa); } void fun(){ // 如果自己已经写了operator new和delete还想调用系统的。则可以写成 A* pa = ::new A(); // :: 全局运算符,表示调用系统的new运算符 ::delete pa; A* pb = new A[3](); // 构造函数被调用了3次,operator new[]/delete[]只被调用了一次 delete[] pb; }