自定義內存操做的意義:前端
- 下降 malloc 調用次數,提升內存空間利用率(每次 malloc 會攜帶上下 cookies[8bytes]標記)
- 下降 malloc 調用次數,提升內存管理速度
#include <cstddef> #include <iostream> using namespace std; class Screen { public: Screen(int x) : i(x) { } int get() { return i; } // 默認 static void *operator new(size_t); // 默認 static void operator delete(void*, size_t); private: Screen *next; // 這種設計會引起多耗用一個 next 的疑慮,下種實現更好 static Screen *freeStore; static const int screenChunk; private: int i; }; Screen *Screen::freeStore = 0; const int Screen::screenChunk = 24; void *Screen::operator new(size_t size) { Screen *p; if (!freeStore) { // linked list 是空的,因此申請一大塊 size_t chunk = screenChunk * size; freeStore = p = reinterpret_cast<Screen*>(new char[chunk]); // 將一大塊分割,看成 linked_list 串起來 for (; p!= &freeStore[screenChunk-1]; ++p) p->next =p + 1; p->next = 0; } p = freeStore; freeStore = freeStore->next; return p; } // 併爲將內存歸還給系統,任由 Screen 接管(不算是內存泄露) void Screen::operator delete(void* p, size_t) { // 講 deleted object 插回 free list 前端 (static_cast<Screen*>(p))->next = freeStore; freeStore = (static_cast<Screen*>(p)); } void func_1() { cout << "==== " << "Screen::operator new" << " ====" << endl; cout << sizeof(Screen) << endl; size_t const N = 100; Screen *p[N]; for (size_t i=0; i<N; ++i) p[i] = new Screen(i); for (size_t i=0; i<10; ++i) cout << p[i] << endl; for (size_t i=0; i<N; ++i) delete p[i]; } void func_2() { cout << "==== " << "::operator new" << " ====" << endl; cout << sizeof(Screen) << endl; size_t const N = 100; Screen *p[N]; for (size_t i=0; i<N; ++i) p[i] = ::new Screen(i); for (size_t i=0; i<10; ++i) cout << p[i] << endl; for (size_t i=0; i<N; ++i) :: delete p[i]; } int main() { func_1(); func_2(); return 0; }
輸出:【如下輸出證實自定義內存管理提升了空間利用率】ios
==== Screen::operator new ==== // 內存間隔 8 8 0x10080e8 0x10080f0 0x10080f8 0x1008100 0x1008108 0x1008110 0x1008118 0x1008120 0x1008128 0x1008130 ==== ::operator new ==== // 內存間隔 16, 包含 8 bytes cookies (上、下) 8 0x1001630 0x10084d0 0x10084e0 0x10084f0 0x1008500 0x1008510 0x1008520 0x1008530 0x1008540 0x1008550
#include <cstddef> #include <iostream> using namespace std; class Airplane { private: struct AirplaneRep { unsigned long miles; char type; }; private: union { AirplaneRep rep; // 此處針對使用中的 object Airplane *next; // 此處針對 free list 上的 object }; public: unsigned long getMiles() { return rep.type; } void set(unsigned long m, char t) { rep.miles = m; rep.type = t; } public: static void *operator new(size_t size); static void operator delete(void *deadObject, size_t size); private: static const int BLOCK_SIZE; static Airplane *headOfFreeList; }; const int Airplane::BLOCK_SIZE = 512; Airplane *Airplane::headOfFreeList = nullptr; void *Airplane::operator new(size_t size) { // 若是大小有誤,轉交給 ::operator new [繼承時發生] if (size != sizeof (Airplane)) return ::operator new(size); Airplane *p = headOfFreeList; if (p) // 若是 p 有效,就把 list 頭部下移一個元素 { headOfFreeList = p->next; } else { // free list 已空,申請(分配)一大塊內存 Airplane *newBlock = static_cast<Airplane*>(::operator new(BLOCK_SIZE *sizeof(Airplane))); // 將小塊串成一個 free list, 但跳過#0, 因它將被傳回看成本次成果 for (int i=1; i<BLOCK_SIZE; ++i) newBlock[i].next = &newBlock[i+1]; newBlock[BLOCK_SIZE-1].next = 0; // 結束 list p = newBlock; headOfFreeList = &newBlock[1]; } return p; } // operator delete 接收一個內存塊,若是大小正確,就把它加到 free list 前端 void Airplane::operator delete(void *deadObject, size_t size) { if (deadObject == 0) return; // 若是大小有誤,轉交給 ::operator delete [繼承時發生] if (size != sizeof(Airplane)) { ::operator delete(deadObject); return; } Airplane *carcass = static_cast<Airplane*>(deadObject); carcass->next = headOfFreeList; headOfFreeList = carcass; } void func_1() { cout << "==== " << "Airplane::operator new" << " ====" << endl; size_t const N =100; Airplane *p[N]; for (size_t i=0; i<N; ++i) p[i] = new Airplane; // 隨機測試 object 是否正常 p[1]->set(100, 'A'); p[5]->set(1000, 'B'); p[9]->set(10000, 'C'); // 輸出前 10 個 pointer, 用以比較其間隔 for (size_t i=0; i<10; ++i) cout << p[i] << endl; for (size_t i=0; i<N; ++i) delete p[i]; } void func_2() { cout << "==== " << "::operator new" << " ====" << endl; size_t const N =100; Airplane *p[N]; for (size_t i=0; i<N; ++i) p[i] = ::new Airplane; // 隨機測試 object 是否正常 p[1]->set(100, 'A'); p[5]->set(1000, 'B'); p[9]->set(10000, 'C'); // 輸出前 10 個 pointer, 用以比較其間隔 for (size_t i=0; i<10; ++i) cout << p[i] << endl; for (size_t i=0; i<N; ++i) ::delete p[i]; } int main() { cout << sizeof(Airplane) << endl; // 注意輸出,考慮字節對齊 !! func_1(); func_2(); return 0; }
輸出:cookie
8 ==== Airplane::operator new ==== // 內存間隔 8 0xed80e8 0xed80f0 0xed80f8 0xed8100 0xed8108 0xed8110 0xed8118 0xed8120 0xed8128 0xed8130 ==== ::operator new ==== // 內存間隔 16, 包含 8 bytes cookies (上、下) 0xed1630 0xed90f0 0xed9100 0xed9110 0xed9120 0xed9130 0xed9140 0xed9150 0xed9160 0xed9170