咱们肯定知道标准库中著名allocator,许多存储器都需要这个东西。我们现在就模仿着写一个,当然肯定没有原来的厉害,而且是单自由链表。
在此先介绍new和delete,c++里面的new分为4种。delete分两种。
| new | delete | 
|---|---|
| 普通new | 普通delete | 
| array new 创建数组的 | 对应的array delete 会调用多次析构函数 | 
| ::operator new 全局的new,分配指定大小的额空间 | |
| replacement new 在指定空间内调用构造函数,不会分配空间 | 
在c语言中,malloc是这些new的底层,最终都要跑到malloc里。如果一个程序需要频繁的申请释放内存,那么可以提一次性申请很多内存,分块给程序。这样就避免调用malloc,加快程序运行时间。

先看看我的测试结果,我创建两类(大小相同),第一个使用自定义分配器,第二个就是普通的new来分配内存。

可以看到,时间是两倍多。下面就看是我写的分配器头文件。
#pragma once
class myAllocator
{
private:
    struct MyMemory
    {
        struct MyMemory* next;
    };
    MyMemory* MemoryHeadPtr = nullptr;      // 内存空间头指针
    unsigned int chunk;                     // 一次创建内存块数量
public:
    myAllocator(unsigned i) :chunk(i) {};   // 构造函数
    void* allocate(size_t size);            // 分配空间
    void deallocate(void* str);             // 归还捏村
};
chunk值得是一次性创建的内存块数量,不同类需要不同的大小和一次的数量,所以就需要用户手动输入。
两个函数的实现如下
#include "myAllocator.h"
void* myAllocator::allocate(size_t size) {
    MyMemory* p;
    if (MemoryHeadPtr == nullptr) {     // 如果没有分配内存或者之前的用完了就再分配,否则返回一块空间
        size_t CHUNK = chunk * size;    // 创建内存的大小
        MemoryHeadPtr = p = reinterpret_cast<MyMemory*>(::operator new(CHUNK));     //头指针指向新内存
        for (int i = 0; i < (chunk - 1); i++) {     //对内存进行分块
            p->next = reinterpret_cast<MyMemory*>((char*)p + size);
        }
        p->next = nullptr;              
    }
    p = MemoryHeadPtr;
    MemoryHeadPtr = MemoryHeadPtr->next;        //头指针后移,因为前面一块用出去了
    return p;
}
void myAllocator::deallocate(void* str) {       
    (reinterpret_cast<MyMemory*>(str))->next = MemoryHeadPtr;       
    MemoryHeadPtr = reinterpret_cast<MyMemory*>(str);
}
最后是我的测试代码。
#include<iostream>
#include"myAllocator.h"
#include<windows.h>
using namespace std;
// 使用自定义分配器的测试类,三个int类型,大小为12字节,
class UsingMyallocator {
private:
    int x, y, z;
    static myAllocator ClassAllocate;
public:
    UsingMyallocator(int i) :x(i), y(i), z(i) {};   //构造函数初始化
    static void* operator new(size_t size) {        //重载new,使用分配器
        return ClassAllocate.allocate(size);
    }
    static void operator delete(void* ptr) {        //重载delete
        return ClassAllocate.deallocate(ptr);
    }
};
myAllocator UsingMyallocator::ClassAllocate(20);    //由于静态......
// 没有使用自定义的分配器的测试类,大小也是12字节
class NoMyallocator {
private:
    int x, y, z;
public:
    NoMyallocator(int i) :x(i), y(i), z(i) {};
};
// 由于的电脑是实验室工作站(嘿嘿),测试只能用微妙级别的时间函数,比较麻烦
// 使用分配器的测试函数
void test1() {
    LARGE_INTEGER nFreq;
    LARGE_INTEGER nBeginTime;
    LARGE_INTEGER nEndTime;
    QueryPerformanceFrequency(&nFreq);
    QueryPerformanceCounter(&nBeginTime);           //开始计时 
    UsingMyallocator* p[1000];                      //创建1000个测试对象,不断地创建和释放。记录时间
    for (int j = 0; j < 1000; j++) {
        for (int i = 0; i < 1000; i++) {
            p[i] = new UsingMyallocator(i);
        }
        for (int i = 0; i < 1000; i++) {
            delete p[i];
        }
    }
    QueryPerformanceCounter(&nEndTime);             //停止计时 
    double time = (double)(nEndTime.QuadPart - nBeginTime.QuadPart) / (double)nFreq.QuadPart;
    cout << "使用分配器测试运行时间:" << time * 1000 << "ms" << endl;
}
//不用分配器的测试函数
void test2() {
    LARGE_INTEGER nFreq;
    LARGE_INTEGER nBeginTime;
    LARGE_INTEGER nEndTime;
    QueryPerformanceFrequency(&nFreq);
    QueryPerformanceCounter(&nBeginTime);
    NoMyallocator* p[1000];                         //创建1000个测试对象,不断地创建和释放。记录时间
    for (int j = 0; j < 1000; j++) {
        for (int i = 0; i < 1000; i++) {
            p[i] = new NoMyallocator(i);
        }
        for (int i = 0; i < 1000; i++) {
            delete p[i];
        }
    }
    QueryPerformanceCounter(&nEndTime);             //停止计时 
    double time = (double)(nEndTime.QuadPart - nBeginTime.QuadPart) / (double)nFreq.QuadPart;
    cout << "没有使用分配器测试运行时间:" << time * 1000 << "ms" << endl;
}
//主函数
int main() {
    test1();
    test2();
    return 0;
}
其实吧,我犯一个大错误!!!!!!!!就是忘记写析构函数了,内存池销毁的时候,应该释放空间的。!!!下面补上
myAllocator::~myAllocator() {
    delete MemoryHeadPtr;
}