咱们肯定知道标准库中著名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;
}