C++ 的内存获取机制:
void* p1 = malloc(512);
free(p1);complex<int>* p2 = new complex<int>;
delete p2;void* p3 = ::operator new(512);
::operator delete(p3);//GNUC
void* p4 = alloc::allocate(512);
alloc::deallocate(p4, 512);//GNUC4.9
void* p5 = allocator<int>().allocate(7); //分配7个int
allocator<int>().deallocate((int*)p5, 7);
表达式 new delete
new的步骤:
- 申请一段指定类大小的空间:new —> operator new —> malloc
- 转化为对应类类型
- 调用类构造函数
在operator new的源码中,有个std::nothrow_t& _THROW0()参数,表示这个函数不抛异常,取而代之的是返回一个空指针,用户通过判断是否为空指针来判断是否分配成功。
array new、array delete
array new是分配一个对象数组,通常容易犯得一个错误是在delete的时候忘记在delete后面加[]导致内存泄漏的问题。
replacement new
允许我们将对象分配在已经构建的内存中
他不会进行内存分配,而是调用重载的operator new,用于返回已经分配好的内存,转型、调用构造函数。
#include<new>
char* buf = new char[sizeof(Complex)* 3];
Complex* pc = new(buf) Complex(1, 2); // replacement new!!!
Complex* pc = new Complex(1, 2);
函数operator new()、operator delete()
重载::operator new / ::operator delete
全局重载:
inline void* operator new(size_t size){cout << "global new() " << endl;return malloc(size);
}inline void* operator new[](size_t size){cout << "global new[]() " << endl;return malloc(size);
}
在类中重载::operator new / ::operator delete更有用(array new / array delete重载也是一样的方法):
我们重载这两个函数,是为了接管内存分配的工作,接管它了有什么用呢?很有用,比如说可以做一个内存池(这个就是之前讲STL的时候的__pool_allocator):
为什么重载的operator new是static呢?因为希望实现的这个内存池是这个类的所有对象都能使用的!
我们可以重载operator new()的前提是:每一个版本的声明都必须有独特的参数列,其中第一个参数必须是size_t,其余参数以new所制定的replacement arguments为初值。
只有在上述的重载replacement new抛出异常的时候,才会调用相应的operator delete(这个需要自己去实现),因为在重载replacement new抛出异常,那么说明内存分配不成功,但是可能已经申请好内存,那么我们应该去处理申请好的这个内存。
static allocator
new handler
=default =delete
delete 我不要,default 使用默认的版本
分配器 allocator
分配器分配途径:allocator—>allocate—>::operator new—>malloc
我们想要把operator new / delete抽取出来形成单独的一个类allocator,是的这个类和内存分配的分配细节剥离开,这样,需要内存管理的类,就调用allocator。这就是STL中分配器的实现思路。
VC6的标准分配器
这个编译器的allocator没有任何特殊设计,单纯是调用malloc,分配是以对象元素为单位。
GNU C 2.9
设计是内存池的思想。16个指针指向16条链表,每条链表分配不同大小的内存空间,从左往右每一条链表间隔8个字节。理论上是这样的,但是在代码实现的时候,是首先申请一个大的内存块,然后在大的内存块上进行切分,所以不同链表之间会有连线。
每个链表会申请nx8x20x2字节的内存空间,n代表第n条链表,20表示将内存最多切分成20个子内存块,2表示会申请2倍大小的内存用于战备。这些内存空间是cookie free的。
如果申请的内存大于128字节,那么就有malloc来管理,就不归这个pool管理了。
源码中deallocate没有free操作(源于先天设计缺陷),即只要被pool申请空间之后,就不会再还回操作系统了。对于一个程序来说,这个也没有什么大不了的,但是对于一台机器来说,不止运行一个程序,这是有弊端的。这可能就是为什么GNU4.9把它替换回去的原因?
参考文章:侯捷C++八部曲笔记(五、内存管理)_侯捷内存管理-CSDN博客