✏️

Memory Allocate

Tags

malloc & free

notion image
malloc分配大内存用mmap进行「私有匿名映射」,小内存用brk进行堆内存指针上移动
brk
brk
mmap
mmap
这个阈值默认为128KB,可能根据glibc版本不同而不同
 
malloc分配的是虚拟内存,即不访问这片内存的话物理内存甚至毫无感知
 
malloc会先分配16字节的内存块头(free的时候用),然后再分配实际内存,返回的是实际内存的首地址
brk会预分配更多的内存作为内存池(比如malloc 1字节但实则在堆上开出100多字节),形成内存池,free的时候不直接回收,而是等待下次申请内存时,如果申请的内存小于内存池大小则分配到内存池里
mmap就会直接回收,所以第一次访问mmap分配的虚拟地址时都会触发缺页中断
 
为什么要根据内存大小控制用哪种方式呢?
全用mmap则每次都需要系统调用,并且第一次访问分配的虚拟地址时一定会触发缺页中断,CPU开销大;
全用brk容易出现内存碎片
根据大小来选择分配方式可以弱化两种方式的缺点
 
 

堆与自由存储区

自由存储区:由new动态分配的内存区域,所有C++编译器默认使用,但是可以通过重载操作符的方式改用其他内存来实现自由存储
 

new & delete

默认实现
补充说明:调用noexcept版本的new时,申请失败不会抛出异常(int* p = new (noexcept) int;),而是抛出个指针
默认实现 补充说明:调用noexcept版本的new时,申请失败不会抛出异常(int* p = new (noexcept) int;),而是抛出个指针
notion image
new的工作原理:
  • 内存分配:调用operator new ([ ]) 分配一块足够大的、原始的、未命名的内存空间
  • 对象构造:调用构造函数构造
  • 返回指向该对象的指针
 
delete工作原理:
  • 调用析构函数
  • operator delete ([ ]) 释放空间
 
编译器发现operator new或delete时,会去查找可供调用的operator函数,类类型会在类和基类的作用域中查找,没找到就在全局作用域(::new)去查找,找到自定义版本的operator函数就调用它,否则调用标准库定义的版本
 
new内置了sizeof、类型转换和类型安全检查功能
返回的是 类型安全的指针(malloc直接返回void*)
创建数组时,只能使用对象的无参constructor,但是可以用初始值列表({A(1, 2), A(1, 3)})初始化
class Obj { public :   Obj(void); // 无参数的构造函数   Obj(int x); // 带一个参数的构造函数 } void Test(void) {  Obj *a = new Obj;  Obj *b = new Obj(1); // 初值为1 Obj *objects = new Obj[100];  delete a;  delete b; delete[] objects; }
 
  • delete和delete[]的区别,delete[]如何知道要delete多少次,在类的成员函数中能否delete This?
    • 对于一个对象数组,其在分配内存的时候会在头部分配4字节的长度,然后对数组的每个对象都会调用一次析构函数
    • 在类的成员函数中可以delete this,并且delete之后还能访问写在.text段的方法(即非虚函数)
 
重载operator new和operator delete
注意operator delete不允许抛出异常(下面的声明有点问题,delete应该返回void)
notion image
size_t是一个对象 / 一个数组所有对象的大小
可以提供其他的重载版本,但是不能重载下面这个版本,因为这个版本只供STL用
void *operator new(size_t, void*);
简单的重载方式:
void* operator new (size_t size) { if (void* mem = malloc(size)) { return mem; } else { throw bad_alloc(); } } void operator delete(void* mem) noexcept { free(mem); }
 

placement new:负责对象构造,将对象构造与内存分配解耦

与operator new相反
notion image
// e.g. 对象池 const int POOL_SIZE = 128; char memoryPool[POOL_SIZE * sizeof(MyClass)]; void createObject(int index, int value) { void* location = &memoryPool[index * sizeof(MyClass)]; new (location) MyClass(value); }
 
Reference:
《C++ Primer》