自己管理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)

猜你喜欢

转载自blog.csdn.net/lmb1612977696/article/details/80012982