new expression
new会做两个动作:1、分配一块内存用来放object;2、分配好之后会调用构造函数。
//一个Person类 Person *p = new Person("liming",16); //初始化姓名和年龄;
new这个表达式会被编译器看作是
Person *p; try{ void *mem = operator new(sizeof(Person)); //operstor new会调用malloc分配内存 p=static_cast<Person*>(mem); p->Person::Person("liming",16); //调用构造函数 } catch (std::bad_alloc) { ... }
delete expression
delete某个object,编译器会先调用析构函数,这个object就会释放掉。
p->~Person(); operator delete(p); //调用free()函数
array new和array delete
//一个person类 Person * p=new Person[3]; //调用三次默认构造 //无法通过参数赋初值 delete [] p; //调用三次析构函数
一个demo
class Person { public: Person() { m_Age = 0; cout << "person的默认构造,this="<<this<<" age= "<<m_Age << endl; } Person(int age) :m_Age(age) { cout << "person的有参构造,this = "<<this<<"age= "<<m_Age << endl; }; ~Person() { cout << "person的析构函数,this= " << this << "age= " << m_Age << endl; } //在类中重载operator new,就不会去走全局作用域下的operator new //所谓内存管理就是把这些动作接管过来,弄一个内存池,但是这里并没做任何处理 static void * operator new(size_t size); static void *operator new(size_t size, void *ptr); //plcement new static void operator delete(void *ptr, size_t size); static void * operator new[](size_t size); static void operator delete(void* ptr1, void* ptr2); //对应placement new的operator delete static void operator delete[](void *ptr, size_t size); private: int m_Age; }; void * Person:: operator new(size_t size) { Person *p = (Person*)malloc(size); cout << "my operator new" << endl; return p; } void * Person:: operator new(size_t size,void *ptr) { return ptr; } void Person::operator delete(void *ptr, size_t size) { free(ptr); cout << "my operator delete" << endl; } void* Person::operator new[](size_t size) { Person *p = (Person*)malloc(size); cout << "my operator new []" << endl; return p; } void Person::operator delete[](void *ptr, size_t size) { free(ptr); cout << "my operator delete[]" << endl; } void Person::operator delete(void *ptr1, void *ptr2) { free(ptr1); cout << "operator delete(void *,void *)" << endl; } void test01() { Person *Parry = new Person[3];//会调用默认构造 Person *temp = Parry; cout << "parry= " << Parry << "temp=" << temp << endl; for (size_t i = 0; i < 3; i++) { new(temp++)Person(i + 10); //有参构造 placement new 允许我们将object构造于已经分配的内存中。 } cout << "parry=" << Parry << "temp=" << temp << endl; delete[] Parry; }
placement new
placement new 允许我们将object构造于已经分配的内存中。但是没有所谓的placement delete,因为placement new没有分配内存。但是在分配好内存之后,如果出现构造失败抛出异常,需要有对应的operator delete来释放这块内存。
以上demo中的new(temp)Person(1),编译器将他转换成
void *mem = operator new(sizeof(Person),temp);//不做事 /*void* operator new(size_t,void *loc) { return loc;}*/ temp = static_cast<Person*>(mem); temp->Person::Person(1);
针对一个class设计出一个内存管理
减少malloc()的次数、减少cookie用量可以节省空间,提高效率。由此可以使用内存池来对内存管理,即一次malloc()一大块内存,再切成若干小块,用户要求几块给几块,剩下的区块用指针连接起来。可以通过重载operator new/operator delete来设计内存池。
设计一个alloctor
class myallocator{ private: struct obj{ struct obj*next; //嵌入式指针 }; public: void * allocate(size_t size); void dellocate(void *, size_t size); private: obj *freeStore = nullptr; const int CHUNK = 10; }; void * myallocator::allocate(size_t size) { obj *p; if (!freeStore) { size_t chunk = CHUNK*size; freeStore = p = (obj*)malloc(chunk);//一次malloc一大块 for (size_t i = 0; i < (CHUNK - 1); i++) { p->next = (obj*)((char*)p + size); p = p->next; } p->next = nullptr; } p = freeStore; freeStore = freeStore->next; return p; //分出去一块 } void myallocator::dellocate(void *p, size_t size) { ((obj*)p)->next = freeStore; freeStore = (obj*)p; }
在一个class中使用内存池
class Person { public: Person() { m_Age = 0; } static void *operator new(size_t size) //重载operator new { return myAlloc.allocate(size); } static void operator delete(void*ptr, size_t size) { return myAlloc.dellocate(ptr, size); } int m_Age; static myallocator myAlloc; }; myallocator Person::myAlloc; void test01() { Person* arry[5]; cout << "sizeof(person)=" << sizeof(Person) << endl; for (size_t i = 0; i < 5; i++) { arry[i] = new Person; cout << arry[i] << " " << arry[i]->m_Age << endl; } for (size_t i = 0; i < 5; i++) { delete arry[i]; } }
内存池
准备工作
enum{ __ALIGN = 8 };//小区块的上调边界 enum{ __MAX_BYTES = 128 };//区块上限 enum { __NFREELISTS = __MAX_BYTES / __ALIGN }; //自由链表的长度 //嵌入式指针 struct obj{ struct obj*free_list_link; };
class alloc{ private: static size_t ROUND_UP(size_t bytes) //上调到8的倍数 { return(((bytes)+__ALIGN - 1) & ~(__ALIGN - 1)); } private: static obj* free_list[__NFREELISTS]; //16个自由链表 //用户要的内存应该由第几号链表负责 static size_t freelist_index(size_t bytes) { return (bytes + __ALIGN - 1) / __ALIGN - 1; } //注水 static void * refill(size_t n); static void *chunk_alloc(size_t size, int &nobjs); static char *start_free; //战备池的开始端 static char * end_free;//战备池的末端 static size_t heap_size;//总的分配量 public: //分配大小为n的空间 static void * allocate(size_t n) { obj **my_free_list;//指向自由链表的起点 obj * result; //要的字节数大于128 if (n > (size_t)__MAX_BYTES) { //交给malloc return (std::malloc(n)); } //由第几号链表负责 my_free_list = free_list + freelist_index(n); result = *my_free_list;//第一块 if (result == 0)//判断这个链表是否为空 { //注水 void * r = refill(ROUND_UP(n)); return r; } //第一块给出去以后,指向第二块 *my_free_list = result->free_list_link; return result; } static void deallocate(void *p, size_t n) { obj*q = (obj*)p; obj ** my_free_list; if (n > (size_t)__MAX_BYTES) { //第一级 std::free(p); return; } my_free_list = free_list + freelist_index(n); q->free_list_link = *my_free_list; *my_free_list = q; } }; //类外初始化 char *alloc::start_free = nullptr; char *alloc::end_free = nullptr; size_t alloc::heap_size = 0; obj * alloc::free_list[__NFREELISTS] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; void *alloc::refill(size_t n) //n是8的倍数 { int nobjs = 20;//预设取20 char * chunk = (char *)chunk_alloc(n, nobjs); obj **my_free_list; obj*result; obj *current_obj; obj*next_obj; int i; if (1 == nobjs) return chunk; my_free_list = free_list + freelist_index(n); result = (obj*)chunk; *my_free_list = next_obj = (obj*)(chunk + n); for (i = 1;; ++i) { current_obj = next_obj; next_obj = (obj*)((char*)next_obj + n); if (nobjs - 1 == i) { current_obj->free_list_link = 0; break; } else { current_obj->free_list_link = next_obj; } } return result; } void *alloc::chunk_alloc(size_t size, int &nobjs) { char * result; size_t total_bytes = size*nobjs; size_t bytes_left = end_free - start_free; if (bytes_left > total_bytes) { //战备池很充足 result = start_free; start_free += total_bytes; return result; } else if (bytes_left >= size){ nobjs = bytes_left / size; total_bytes = size*nobjs; result = start_free; start_free += total_bytes; return result; } else {//战备池不足以满足一个 size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4); if (bytes_left > 0) { obj **my_free_list = free_list + freelist_index(bytes_left); //处理碎片 ((obj*)start_free)->free_list_link = *my_free_list; *my_free_list = (obj*)start_free; } start_free = (char *)malloc(bytes_to_get); if (0 == start_free) { int i; obj **my_free_list; obj *p; for (i = size; i < __MAX_BYTES; i += __ALIGN) { my_free_list = free_list + freelist_index(i); p = *my_free_list; if (0 != p) { *my_free_list = p->free_list_link; start_free = (char *)p; end_free = start_free + i; return (chunk_alloc(size, nobjs)); } } // std::printf("out of memory"); end_free = nullptr; throw std::bad_alloc(); } heap_size += bytes_left; end_free = start_free + bytes_to_get; return(chunk_alloc(size, nobjs)); } } }
测试程序
class Person { public: Person() { m_Age = 0; } static void *operator new(size_t size) //重载operator new { return myAlloc.allocate(size); } static void operator delete(void*ptr, size_t size) { return myAlloc.deallocate(ptr, size); } int m_Age; static alloc myAlloc; }; alloc Person::myAlloc; int main() { Person* arry[5]; std::cout << "sizeof(person)=" << sizeof(Person) << std::endl; for (size_t i = 0; i < 5; i++) { arry[i] = new Person; std::cout << arry[i] << " " << arry[i]->m_Age << std::endl; } for (size_t i = 0; i < 5; i++) { delete arry[i]; } system("pause"); }