- new与placement new
-
new:
- 先调用operator new(大小),而operator new()会调用malloc尝试分配内存,失败则调用_callnewh()来释放内存,直至分配成功
- 可以设置分配失败的处理函数:将写好的处理函数作为参数传入set_new_handler即可
- 然后将得到的指针转型
- 最后通过指针调用构造函数
- 先调用operator new(大小),而operator new()会调用malloc尝试分配内存,失败则调用_callnewh()来释放内存,直至分配成功
-
placement new
- 先调用operator new(大小, address),该带2个参数的函数直接返回buf,不做任何改动,即不分配内存。
- 然后将得到的指针转型
- 最后通过指针调用构造函数
-
总结:new会分配内存后调用构造函数,而placement new相当于只是调用构造函数。因此我们可以像下面这样模拟new的行为:
-
容器的内存分配方式
当元素放入容器时,容器也需要为其分配一块空间,但其不是用的new和delete,而是将其包装在construct()和destroy()函数中 -
设计一个内存池
- 重载局部的operator new()
-
方法1:单独多使用一些指针来将空闲块连成链表
下面在节点中使用next指针来将小块链接起来
void* A::operator new(size_t size) {cout << "局部new" << endl;A* p;if (!A::freeStore){//申请一大块空间//A::freeStore = (A*)malloc(size * Chunk);A::freeStore = reinterpret_cast<A*>(new char[Chunk*size]);p = A::freeStore;//初始化p指针也指向头节点//串成链表for (int i = 0; i < Chunk; i++){p->next = p + 1;//地址增大4,就是一个A的大小p = p->next;}p->next = NULL;}//把链表头部的空闲块拿出来用p = A::freeStore;A::freeStore = A::freeStore->next;return p; }
-
使用嵌入式指针:也就是指针临时借用一下空闲块里的空间,等到需要分配出去使用时就正常使用即可。
下面的rep和next占用同一片空间
class A { private://数据struct Airplane//占8字节{int miles;char type;}; private:union{Airplane rep;A* next;};static A* freeStore;//指向链表的头部的指针static const int Chunk = 3;//内存池容纳几个 public:static void* operator new(size_t size);static void operator delete(void* ptr);void set(int m, char t)....void show().... };
-
- 重载局部的operator delete()
- 采用头插法,将空闲块插入到链表头
void A::operator delete(void* ptr) {cout << "局部delete" << endl;//头插法static_cast<A*>(ptr)->next = A::freeStore;A::freeStore = static_cast<A*>(ptr); }
- 采用头插法,将空闲块插入到链表头
- c语言版本的内存池
- 先写个宏定义
#define malloc(mp, size) _malloc(mp, size) #define free(mp, ptr) _free(mp, ptr)
- 定义一个大的内存块,这里称其为页
typedef struct mempool_s {int block_size;//一小块的大小int free_count;//该页内剩余空闲块的个数void *mem;//指向该页首地址void *ptr;//指向该页中最新创建的块的地址(即下次要分配出去内存的块) } mempool_t;
- 写一个内存池初始化函数,将128个小块串成链表
int memp_init(mempool_t *mp, size_t block_size) {printf("block_size: %ld\n", block_size);if (!mp) return -1;memset(mp, 0, sizeof(mempool_t));mp->block_size = block_size;mp->free_count = MEM_PAGE_SIZE / block_size;mp->mem = malloc(MEM_PAGE_SIZE);if(!mp->mem) return -1;mp->ptr = mp->mem;//把该页中的128块串成链表char *ptr = mp->ptr;//ptr指针指向第1块for (int i = 0; i < mp->free_count; i++){//使用2级指针:一级指针ptr,(char**)ptr将其强转为指向char*的指针,//*(char**)ptr为其指向的char*地址,将该地址赋值为ptr所指块的下一块地址*(char**)ptr = ptr + block_size;ptr += block_size;}*(char**)ptr = NULL;//最后一块的前几个字节保存的是NULLreturn 0; }
- 先写个宏定义
- 最后写内存分配与释放的函数即可。释放时同样使用头插法
- 重载局部的operator new()
- G2.9 alloc的大致流程:page8