1. C++内存分配调用过程
上图中,ptmalloc,tcmalloc与jemalloc等是malloc底层实现策略。相比之下,ptmalloc性能较弱,资源消耗较多,在高CPU核心数情况下jemalloc比tcmalloc性能要好。
总之,内存池管理主要针对小内存分配进行,而大内存块由系统调用进行分配,如mmap内存映射。
C/C++内存分配原语有malloc,new,::operator new()和allocate(),其中可否重载关系如下:
分配 | 释放 | 类别 | 可否重载 |
---|---|---|---|
malloc() | free() | C语言 | 不可 |
new | delete | C++表达式 | 不可 |
operator new() | operator delete() | C++函数 | 可 |
allocator::allocate() | allocator::deallocate() | C++标准库空间分配器 | 视情况而定 |
2. C++中new/delete的四种形式
1)::operator new/::operator delete 这是全局的new/delete,只是简单的对malloc/free 进行封装。当使用不带属性限定符(::)的operator new/operator delete时,如果没有重载,系统会调用全局的new/delete分配空间。
2)new expression new表达式,编译器会将其翻译为三条语句:
// ---------------- 分配空间 ---------------- //
obj_class* mem = new obj_class(init_val);
// 翻译为以下三条语句
void* mem = operator new(sizeof(obj_class)); // 使用new分配空间,其实质使用malloc分配
mem = static_cast<obj_class*>(mem); // 强制转型
mem->obj_class(init_val); // 使用obj_class构造函数进行初始化
// ---------------- 释放空间 ---------------- //
delete mem;
// 翻译为以下两条语句
obj_class::~obj_class(mem); // 调用析构函数
operator delete(mem); // 释放空间
3)array new new多个数组,例如:
type* ptr = new typep[size]; // 分配空间
delete[] ptr; // 释放空间
PS:当type的析构函数是无意义的,即 is_trivially_destructible::value == true,此时释放空间时,可以不加"[]",也不会出现内存泄露。当然,最好加上"[]",这样代码更加友好。
4)placement new 除了必须的第一个参数,还含有额外的参数的operator new 的重载。
注:在正常调用placement new时,使用delete ptr释放内存;只有当调用placement new抛出异常时,系统会调用用户重载的placement delete进行处理,防止内存泄露。
3. new handler
当系统调用new分配内存抛出异常 bad_alloc_exception 之前,会调用(不止一次)用户可指定的handler进行处理。而new handler用于出现exception时,用户指定程序的处理方法,其形式如下。
typedef void(*new_handler)(); // 定义的handler函数指针
new_handler set_new_handler(new_handler ptr) throw(); // 设置新的 handler 处理函数
一般处理方法是调用abort()或者exit()。
注:本文主要参照侯捷老师的《内存管理》讲解。