1. 程式人生 > >自己管理C++記憶體(記憶體池)

自己管理C++記憶體(記憶體池)

記憶體管理的目的:提高速度,降低空間浪費率

  1. 減少malloc的使用。(可以先分配一大塊,再一點一點的使用)
  2. 較少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等類中重複的東西,用巨集代替:
這裡寫圖片描述

global allocator(標準版的allocator)