自己管理C++記憶體(記憶體池)
阿新 • • 發佈:2019-01-28
記憶體管理的目的:提高速度,降低空間浪費率
- 減少malloc的使用。(可以先分配一大塊,再一點一點的使用)
- 較少cookie的使用。
版本一
#include <iostream>
using namespace std;
class Screen {
public:
Screen(int x):i(x) {}
int get() { return i; }
void* operator new(size_t);
void operator delete(void*, size_t);
private:
Screen* next; // 為了去掉cookie
static Screen* freeStore;
static const int screenChunk;
private:
int i;
};
Screen* Screen::freeStore = 0;
const int Screen::screenChunk = 24; // 建立24份,記憶體池
void* Screen::operator new(size_t size) {
Screen* p;
if (!freeStore) {
std::cout << "operator new" << std ::endl;
//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;
}
void Screen::operator delete(void* p, size_t) {
//將deleted object 插入free list前端
(static_cast<Screen*>(p))->next = freeStore;
freeStore = static_cast<Screen*>(p);
}
int main() {
cout << sizeof(int) << endl;
cout << sizeof(Screen) << endl;
size_t const N = 100;
Screen* p[N];
for (int i = 0; i < N; ++i) {
p[i] = new Screen(i);
}
//輸出前10個指標,比較其間隔,確認其沒有cookie
for (int i = 0; i < 10; ++i) {
cout << p[i] << endl;
}
for (int i = 0; i < N; ++i) {
delete p[i];
}
return 0;
}
版本二
引入了union的使用
#include <iostream>
using namespace std;
class Airplane {
private:
struct AirplaneRep {
unsigned long miles;
char type;
};
private:
union {
AirplaneRep rep; //此指標對使用中的objects
Airplane* next; //此指標對free list 上的object
};
public:
unsigned long getMiles() { return rep.miles; }
char getType() { 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);
public:
static const int BLOCK_SIZE;
static Airplane* headOfFreeList;
};
Airplane* Airplane::headOfFreeList;
const int Airplane::BLOCK_SIZE = 512;
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-1; ++i) {
newBlock[i].next = &newBlock[i+1];
}
newBlock[BLOCK_SIZE-1].next = 0;
p = newBlock;
headOfFreeList = &newBlock[1];
}
return p;
}
void Airplane::operator delete(void* deadObject, size_t size) {
if (deadObject == 0) {
return;
}
if (size != sizeof(Airplane)) {
::operator delete(deadObject);
return;
}
Airplane* carcass = static_cast<Airplane*> (deadObject);
carcass->next = headOfFreeList;
headOfFreeList = carcass;
}
int main(int argc, char *argv[]) {
cout << sizeof(Airplane) << endl;
size_t const N = 100;
Airplane* p[N];
for(int i = 0; i < N; ++i) {
p[i] = new Airplane;
}
p[1] ->set(1000, 'A');
p[5] ->set(2000, 'B');
p[6] ->set(50000, 'C');
for (int i = 0; i < 10; ++i) {
cout << p[i] << endl;
}
for (int i = 0; i < N; ++i) {
delete p[i];
}
return 0;
}
兩個版本都存在遺憾,申請的記憶體,不能及時還給系統,被自己儲存起來。
static allocator(版本三)
上面的兩個版本,需要在每個class中重複寫member operator new 和 member operator delete。所有避免麻煩,將這個重複的操作包裝起來:
#include <iostream>
using namespace std;
class Allocator {
private:
struct obj {
struct obj* next; // embedded pointer
};
public:
void* allocate(size_t);
void deallocate(void*, size_t);
private:
obj* freeStore = nullptr;
const int CHUNK = 5;
};
void* Allocator::allocate(size_t size) {
obj* p;
if (!freeStore) {
//linked list為空,於是申請一大塊
size_t chunk = CHUNK*size;
freeStore = p = (obj*)malloc(chunk);
//將分配得來的一大塊當做linked list,小塊小塊串起來
for (int i = 0; i < (CHUNK-1); ++i) {
p->next = (obj*)((char*)p + size);
p = p->next;
}
p->next = nullptr; //last
}
p = freeStore;
freeStore = freeStore->next;
return p;
}
void Allocator::deallocate(void* p, size_t) {
//將*p收回插入free list前端
((obj*)p)->next = freeStore;
freeStore = (obj*)p;
}
class Foo {
public:
long L;
string str;
static Allocator myAlloc;
public:
Foo(long l) : L(l) {}
static void* operator new(size_t size) {
return myAlloc.allocate(size);
}
static void operator delete(void* pdead, size_t size) {
return myAlloc.deallocate(pdead, size);
}
};
Allocator Foo::myAlloc;
int main(int argc, char *argv[]) {
Foo foo(10);
return 0;
}
macro(巨集) for static allcoator(版本四)
將版本三Foo等類中重複的東西,用巨集代替: