6.单线程内存池
1. 频繁地分配和回收内存会严重影响性能,通过开发专用的内存管理器可以解决这个问题。
2. 对专用内存管理器的设计至少要从两个方面考虑:大小和并发。
从大小的角度分为以下两种:
(1)、固定大小:分配固定大小内存块的内存管理器。
(2)、可变大小:分配任意大小内存块的内存管理器。所请求分配的大小事先是未知的。
从并发的角度也分为以下两种:
(1)、单线程:内存管理器局限在一个线程内。内存被一个线程使用,并且不越出该线程的界限。这种内存管理器不涉及相互访问的多线程。
(2)、多线程:内存管理器被多个线程并发地使用。这种实现需要包含互斥执行的代码段。无论什么时候,只能有一个线程在执行一个代码段。
案例:
- 版本0:全局函数new()和delete()
#include <iostream>
#include <windows.h>
static LARGE_INTEGER cpuFreq;
static LARGE_INTEGER startTime;
static LARGE_INTEGER endTime;
static double run_time = 0.0;
using namespace std;
class Rational0 //一百万次运行:73.3ms
{
public:
Rational0(int a = 0, int b = 1) : n(a),d(b) {}
private:
int n; // 分子
int d; // 分母
};
int main()
{
Rational0 *array0[1000];
QueryPerformanceFrequency(&cpuFreq); //获取系统时钟的频率
QueryPerformanceCounter(&startTime);
for (int i = 0; i < 1000; i++) {
for (int j = 0; j < 1000; j++) {
array0[j] = new Rational0(j);
}
for (int k = 0; k < 1000; k++) {
delete array0[k];
}
}
QueryPerformanceCounter(&endTime);
run_time = (((endTime.QuadPart - startTime.QuadPart) * 1000.0) / cpuFreq.QuadPart);
cout << "run_time: "<< run_time <<"ms" << endl;
Rational2::deleteMemPool();
while(1);
}
- 版本1:专用内存管理器
#include <iostream>
#include <windows.h>
static LARGE_INTEGER cpuFreq;
static LARGE_INTEGER startTime;
static LARGE_INTEGER endTime;
static double run_time = 0.0;
using namespace std;
class NextOnFreeList { //声明一个辅助结构来连接空闲列表的相邻元素
public:
NextOnFreeList* next;
};
/*需求:避免频繁使用默认内存管理器,原理是先分配指定大小的内存空间,当空间使用完时再分配*/
class Rational1 { //一百万次运行:9.03ms
public:
Rational1(int a = 0, int b = 1) : n(a),d(b) {}
//Rational2的操作符new()和delete()用来管理静态列表。重载全局的new()和delete()。
inline void* operator new(size_t size);
inline void operator delete(void* doomed);
static void newMemPool() { expandTheFreeList(); }
static void deleteMemPool();
private:
static NextOnFreeList* freeList; //空闲静态列表
static void expandTheFreeList(); //静态成员函数,避免从新生成一个类变量,可以节省内存,方便调用,但不能访问类中的非静态成员
enum { EXPANSION_SIZE = 32};
int n; // 分子
int d; // 分母
};
NextOnFreeList* Rational1::freeList = nullptr;
inline void* Rational1::operator new(size_t size)
{
if(nullptr == freeList){
expandTheFreeList(); //列表为空时,扩展
}
NextOnFreeList *head = freeList;
freeList = head->next;
return head;
}
inline void Rational1::operator delete(void* doomed)
{
NextOnFreeList *head = static_cast<NextOnFreeList *>(doomed);
head->next = freeList;
freeList = head;
}
void Rational1::expandTheFreeList() //
{
//必须分配足够大的对象以包含下一个指针
size_t size = (sizeof (Rational1) > sizeof (NextOnFreeList *)) ? sizeof (Rational1) : sizeof (NextOnFreeList *);
NextOnFreeList* runner = static_cast<NextOnFreeList*>((void*)new char[size]);
freeList = runner;
for (int i = 0; i < EXPANSION_SIZE; ++i) {
//修改runner的地址同时也修改了freeList,因为是指针类型,并将runner->next强制转换成NextOnFreeList*类型
runner->next = static_cast<NextOnFreeList*>((void*)new char[size]);
runner = runner->next;
}
runner->next = nullptr;
}
void Rational1::deleteMemPool()
{
NextOnFreeList* nextPtr;
for (nextPtr = freeList; nextPtr != nullptr; nextPtr = freeList) {
freeList = freeList->next;
delete [] nextPtr;
}
}
int main()
{
Rational1 *array1[1000];
Rational1::newMemPool();
QueryPerformanceFrequency(&cpuFreq); //获取系统时钟的频率
QueryPerformanceCounter(&startTime);
for (int i = 0; i < 1000; i++) {
for (int j = 0; j < 1000; j++) {
array1[j] = new Rational1(j);
}
for (int k = 0; k < 1000; k++) {
delete array1[k];
}
}
QueryPerformanceCounter(&endTime);
run_time = (((endTime.QuadPart - startTime.QuadPart) * 1000.0) / cpuFreq.QuadPart);
cout << "run_time: "<< run_time <<"ms" << endl;
Rational1::deleteMemPool();
while(1);
}
- 版本2:固定大小对象的内存池
#include <iostream>
#include <windows.h>
static LARGE_INTEGER cpuFreq;
static LARGE_INTEGER startTime;
static LARGE_INTEGER endTime;
static double run_time = 0.0;
using namespace std;
/*需求:希望内存管理器适用于其他不同的大小类型*/
//MemoryPool类的作用是维护空闲列表
template <class T> //声明一个模板,虚拟类型名为T
class MemoryPool //类模板名为MemoryPool
{
public:
MemoryPool(size_t size = EXPANSION_SIZE);
~MemoryPool();
//从空闲列表中分配T元素
inline void* alloc(size_t size);
//返回T元素到空闲列表中
inline void free(void *doomed);
private:
//空闲列表的下一个元素
MemoryPool<T> *next;
//空闲列表为空时,按照指定大小扩展
enum {EXPANSION_SIZE = 32};
//添加空闲元素至空闲列表
void expandTheFreeList(int list_size = EXPANSION_SIZE);
};
template <class T>
MemoryPool<T>::MemoryPool(size_t size)
{
expandTheFreeList(size);
}
template <class T>
MemoryPool<T>::~MemoryPool()
{
MemoryPool<T> *nextPtr = next;
for (nextPtr = next; nextPtr != nullptr; nextPtr = next) {
next = next->next;
delete [] nextPtr;
}
}
template <class T>
void* MemoryPool<T>::alloc(size_t size)
{
if(nullptr == next){
expandTheFreeList(); //列表为空时,扩展
}
MemoryPool<T> *head = next;
next = head->next;
return head;
}
template <class T>
void MemoryPool<T>::free(void* doomed)
{
MemoryPool<T> *head = static_cast<MemoryPool<T> *>(doomed);
head->next = next;
next = head;
}
/*用途:向空闲列表添加新元素。在空闲列表用尽时被调用*/
template <class T>
void MemoryPool<T>::expandTheFreeList(int list_size)
{
size_t size = (sizeof (T) > sizeof (MemoryPool<T>*)) ? sizeof (T) : sizeof (MemoryPool<T>*);
//从堆上分配新元素
MemoryPool<T>* runner = static_cast<MemoryPool<T>*>((void*)new char[size]);
//将新元素连接到列表中
next = runner;
//分配固定大小的内存
for (int i = 0; i < list_size; ++i) {
//修改runner的地址同时也修改了freeList,因为是指针类型,并将runner->next强制转换成NextOnFreeList*类型
runner->next = static_cast<MemoryPool*>((void*)new char[size]);
runner = runner->next;
}
runner->next = nullptr;
}
class Rational2 { //运行时间:12.07ms
public:
Rational2(int a = 0, int b = 1) : n(a),d(b) {}
inline void* operator new(size_t size){ return memPool->alloc(size); }
inline void operator delete(void* doomed){ return memPool->free(doomed); }
static void newMemPool() { memPool = new MemoryPool<Rational2>; }
static void deleteMemPool(){ delete memPool; }
private:
static MemoryPool<Rational2>* memPool;
static void expandTheFreeList();
enum { EXPANSION_SIZE = 32};
int n; // 分子
int d; // 分母
};
MemoryPool<Rational2>* Rational2::memPool = nullptr;
int main()
{
Rational2 *array3[1000];
Rational2::newMemPool();
QueryPerformanceFrequency(&cpuFreq); //获取系统时钟的频率
QueryPerformanceCounter(&startTime);
for (int i = 0; i < 1000; i++) {
for (int j = 0; j < 1000; j++) {
array3[j] = new Rational2(j);
}
for (int k = 0; k < 1000; k++) {
delete array3[k];
}
}
QueryPerformanceCounter(&endTime);
run_time = (((endTime.QuadPart - startTime.QuadPart) * 1000.0) / cpuFreq.QuadPart);
cout << "run_time: "<< run_time <<"ms" << endl;
Rational2::deleteMemPool();
while(1);
}
版本3:单线程可变大小内存管理器
#include <iostream>
#include <windows.h>
static LARGE_INTEGER cpuFreq;
static LARGE_INTEGER startTime;
static LARGE_INTEGER endTime;
static double run_time = 0.0;
using namespace std;
/*需求:当我们一开始无法判断数据所需内存的大小时,需要设计可变大小的内存管理器*/
//MemoryChunk代替前面的NextOnFreeList类,作用:把不同大小的内存块连接成块序列
class MemoryChunk
{
public:
MemoryChunk(MemoryChunk *nextChunk, size_t reqSize);
~MemoryChunk(){delete [] mem;}
inline void *alloc(size_t size);
inline void free(void* someElement){}
//指向列表下一个内存块
MemoryChunk *nextMemoryChunk() {return next;}
//检查当前剩余的内存空间
size_t spaceAvailable() {return chunkSize - byteAlreadyAllocated;}
//默认分配的内存空间
enum {DEFAULT_CHUNK_SIZE = 4096};
private:
MemoryChunk *next;
//要分配的对象
void *mem;
//一个内存块的默认大小
size_t chunkSize;
//当前已经分配的字节数
size_t byteAlreadyAllocated;
};
MemoryChunk::MemoryChunk(MemoryChunk *nextChunk, size_t reqSize)
{
//确认内存块的适当大小
chunkSize = (reqSize > DEFAULT_CHUNK_SIZE)? reqSize :DEFAULT_CHUNK_SIZE;
next = nextChunk;
//这是全新的构造函数,当前已经分配的字节数为0
byteAlreadyAllocated = 0;
//根据内存块的适当大小,分配内存空间
mem = new char[chunkSize];
}
//内存分配请求,返回一个指向mem所指向的MemoryChunk中的可用空间
void* MemoryChunk::alloc(size_t size)
{
void *addr = static_cast<void *>(static_cast<char*>(mem) + byteAlreadyAllocated);
//记录已经分配的内存大小
byteAlreadyAllocated += size;
return addr;
}
class ByteMemoryPool
{
public:
ByteMemoryPool(size_t initSize = MemoryChunk::DEFAULT_CHUNK_SIZE);
~ByteMemoryPool();
inline void *alloc(size_t size);
inline void free(void* someElement) {listOfMemoryChunk->free(someElement);}
private:
//内存块列表
MemoryChunk *listOfMemoryChunk;
//添加内存块
void expandStorage(size_t reqSize);
};
//创建对象,生成私有存储空间
ByteMemoryPool::ByteMemoryPool(size_t initSize)
{
expandStorage(initSize);
}
//释放内存空间
ByteMemoryPool::~ByteMemoryPool()
{
MemoryChunk *memChunk = listOfMemoryChunk;
while (memChunk) {
listOfMemoryChunk = memChunk->nextMemoryChunk();
delete memChunk;
memChunk = listOfMemoryChunk;
}
}
void* ByteMemoryPool::alloc(size_t size)
{
size_t space = listOfMemoryChunk->spaceAvailable();
//所需要的空间大于实践剩余空间,就申请内存
if(space < size){
expandStorage(size);
}
return listOfMemoryChunk->alloc(size);
}
void ByteMemoryPool::expandStorage(size_t reqSize)
{
listOfMemoryChunk = new MemoryChunk(listOfMemoryChunk,reqSize);
}
class Rational3 { //运行时间:20.1893ms
public:
Rational3(int a = 0, int b = 1) : n(a),d(b) {}
inline void* operator new(size_t size){ return memPool->alloc(size); }
inline void operator delete(void* doomed){ return memPool->free(doomed); }
static void newMemPool() { memPool = new ByteMemoryPool; }
static void deleteMemPool(){ delete memPool; }
private:
static ByteMemoryPool* memPool;
static void expandTheFreeList();
enum { EXPANSION_SIZE = 32};
int n; // 分子
int d; // 分母
};
ByteMemoryPool* Rational3::memPool = nullptr;
int main()
{
Rational3 *array3[1000];
Rational3::newMemPool();
QueryPerformanceFrequency(&cpuFreq); //获取系统时钟的频率
QueryPerformanceCounter(&startTime);
for (int i = 0; i < 1000; i++) {
for (int j = 0; j < 1000; j++) {
array3[j] = new Rational3(j);
}
for (int k = 0; k < 1000; k++) {
delete array3[k];
}
}
QueryPerformanceCounter(&endTime);
run_time = (((endTime.QuadPart - startTime.QuadPart) * 1000.0) / cpuFreq.QuadPart);
cout << "run_time: "<< run_time <<"ms" << endl;
Rational3::deleteMemPool();
while(1);
}
增加了分配逻辑的复杂程度,版本3比版本1,2稍慢,但是易用性更高。
3. 要点:
(1). 内存管6.单线程内存池
1. 频繁地分配和回收内存会严重影响性能,通过开发专用的内存管理器可以解决这个问题。
2. 对专用内存管理器的设计至少要从两个方面考虑:大小和并发。
从大小的角度分为以下两种:
(1)、固定大小:分配固定大小内存块的内存管理器。
(2)、可变大小:分配任意大小内存块的内存管理器。所请求分配的大小事先是未知的。
从并发的角度也分为以下两种:
(1)、单线程:内存管理器局限在一个线程内。内存被一个线程使用,并且不越出该线程的界限。这种内存管理器不涉及相互访问的多线程。
(2)、多线程:内存管理器被多个线程并发地使用。这种实现需要包含互斥执行的代码段。无论什么时候,只能有一个线程在执行一个代码段。
案例:
- 版本0:全局函数new()和delete()
#include <iostream>
#include <windows.h>
static LARGE_INTEGER cpuFreq;
static LARGE_INTEGER startTime;
static LARGE_INTEGER endTime;
static double run_time = 0.0;
using namespace std;
class Rational0 //一百万次运行:73.3ms
{
public:
Rational0(int a = 0, int b = 1) : n(a),d(b) {}
private:
int n; // 分子
int d; // 分母
};
int main()
{
Rational0 *array0[1000];
QueryPerformanceFrequency(&cpuFreq); //获取系统时钟的频率
QueryPerformanceCounter(&startTime);
for (int i = 0; i < 1000; i++) {
for (int j = 0; j < 1000; j++) {
array0[j] = new Rational0(j);
}
for (int k = 0; k < 1000; k++) {
delete array0[k];
}
}
QueryPerformanceCounter(&endTime);
run_time = (((endTime.QuadPart - startTime.QuadPart) * 1000.0) / cpuFreq.QuadPart);
cout << "run_time: "<< run_time <<"ms" << endl;
Rational2::deleteMemPool();
while(1);
}
- 版本1:专用内存管理器
#include <iostream>
#include <windows.h>
static LARGE_INTEGER cpuFreq;
static LARGE_INTEGER startTime;
static LARGE_INTEGER endTime;
static double run_time = 0.0;
using namespace std;
class NextOnFreeList { //声明一个辅助结构来连接空闲列表的相邻元素
public:
NextOnFreeList* next;
};
/*需求:避免频繁使用默认内存管理器,原理是先分配指定大小的内存空间,当空间使用完时再分配*/
class Rational1 { //一百万次运行:9.03ms
public:
Rational1(int a = 0, int b = 1) : n(a),d(b) {}
//Rational2的操作符new()和delete()用来管理静态列表。重载全局的new()和delete()。
inline void* operator new(size_t size);
inline void operator delete(void* doomed);
static void newMemPool() { expandTheFreeList(); }
static void deleteMemPool();
private:
static NextOnFreeList* freeList; //空闲静态列表
static void expandTheFreeList(); //静态成员函数,避免从新生成一个类变量,可以节省内存,方便调用,但不能访问类中的非静态成员
enum { EXPANSION_SIZE = 32};
int n; // 分子
int d; // 分母
};
NextOnFreeList* Rational1::freeList = nullptr;
inline void* Rational1::operator new(size_t size)
{
if(nullptr == freeList){
expandTheFreeList(); //列表为空时,扩展
}
NextOnFreeList *head = freeList;
freeList = head->next;
return head;
}
inline void Rational1::operator delete(void* doomed)
{
NextOnFreeList *head = static_cast<NextOnFreeList *>(doomed);
head->next = freeList;
freeList = head;
}
void Rational1::expandTheFreeList() //
{
//必须分配足够大的对象以包含下一个指针
size_t size = (sizeof (Rational1) > sizeof (NextOnFreeList *)) ? sizeof (Rational1) : sizeof (NextOnFreeList *);
NextOnFreeList* runner = static_cast<NextOnFreeList*>((void*)new char[size]);
freeList = runner;
for (int i = 0; i < EXPANSION_SIZE; ++i) {
//修改runner的地址同时也修改了freeList,因为是指针类型,并将runner->next强制转换成NextOnFreeList*类型
runner->next = static_cast<NextOnFreeList*>((void*)new char[size]);
runner = runner->next;
}
runner->next = nullptr;
}
void Rational1::deleteMemPool()
{
NextOnFreeList* nextPtr;
for (nextPtr = freeList; nextPtr != nullptr; nextPtr = freeList) {
freeList = freeList->next;
delete [] nextPtr;
}
}
int main()
{
Rational1 *array1[1000];
Rational1::newMemPool();
QueryPerformanceFrequency(&cpuFreq); //获取系统时钟的频率
QueryPerformanceCounter(&startTime);
for (int i = 0; i < 1000; i++) {
for (int j = 0; j < 1000; j++) {
array1[j] = new Rational1(j);
}
for (int k = 0; k < 1000; k++) {
delete array1[k];
}
}
QueryPerformanceCounter(&endTime);
run_time = (((endTime.QuadPart - startTime.QuadPart) * 1000.0) / cpuFreq.QuadPart);
cout << "run_time: "<< run_time <<"ms" << endl;
Rational1::deleteMemPool();
while(1);
}
- 版本2:固定大小对象的内存池
#include <iostream>
#include <windows.h>
static LARGE_INTEGER cpuFreq;
static LARGE_INTEGER startTime;
static LARGE_INTEGER endTime;
static double run_time = 0.0;
using namespace std;
/*需求:希望内存管理器适用于其他不同的大小类型*/
//MemoryPool类的作用是维护空闲列表
template <class T> //声明一个模板,虚拟类型名为T
class MemoryPool //类模板名为MemoryPool
{
public:
MemoryPool(size_t size = EXPANSION_SIZE);
~MemoryPool();
//从空闲列表中分配T元素
inline void* alloc(size_t size);
//返回T元素到空闲列表中
inline void free(void *doomed);
private:
//空闲列表的下一个元素
MemoryPool<T> *next;
//空闲列表为空时,按照指定大小扩展
enum {EXPANSION_SIZE = 32};
//添加空闲元素至空闲列表
void expandTheFreeList(int list_size = EXPANSION_SIZE);
};
template <class T>
MemoryPool<T>::MemoryPool(size_t size)
{
expandTheFreeList(size);
}
template <class T>
MemoryPool<T>::~MemoryPool()
{
MemoryPool<T> *nextPtr = next;
for (nextPtr = next; nextPtr != nullptr; nextPtr = next) {
next = next->next;
delete [] nextPtr;
}
}
template <class T>
void* MemoryPool<T>::alloc(size_t size)
{
if(nullptr == next){
expandTheFreeList(); //列表为空时,扩展
}
MemoryPool<T> *head = next;
next = head->next;
return head;
}
template <class T>
void MemoryPool<T>::free(void* doomed)
{
MemoryPool<T> *head = static_cast<MemoryPool<T> *>(doomed);
head->next = next;
next = head;
}
/*用途:向空闲列表添加新元素。在空闲列表用尽时被调用*/
template <class T>
void MemoryPool<T>::expandTheFreeList(int list_size)
{
size_t size = (sizeof (T) > sizeof (MemoryPool<T>*)) ? sizeof (T) : sizeof (MemoryPool<T>*);
//从堆上分配新元素
MemoryPool<T>* runner = static_cast<MemoryPool<T>*>((void*)new char[size]);
//将新元素连接到列表中
next = runner;
//分配固定大小的内存
for (int i = 0; i < list_size; ++i) {
//修改runner的地址同时也修改了freeList,因为是指针类型,并将runner->next强制转换成NextOnFreeList*类型
runner->next = static_cast<MemoryPool*>((void*)new char[size]);
runner = runner->next;
}
runner->next = nullptr;
}
class Rational2 { //运行时间:12.07ms
public:
Rational2(int a = 0, int b = 1) : n(a),d(b) {}
inline void* operator new(size_t size){ return memPool->alloc(size); }
inline void operator delete(void* doomed){ return memPool->free(doomed); }
static void newMemPool() { memPool = new MemoryPool<Rational2>; }
static void deleteMemPool(){ delete memPool; }
private:
static MemoryPool<Rational2>* memPool;
static void expandTheFreeList();
enum { EXPANSION_SIZE = 32};
int n; // 分子
int d; // 分母
};
MemoryPool<Rational2>* Rational2::memPool = nullptr;
int main()
{
Rational2 *array3[1000];
Rational2::newMemPool();
QueryPerformanceFrequency(&cpuFreq); //获取系统时钟的频率
QueryPerformanceCounter(&startTime);
for (int i = 0; i < 1000; i++) {
for (int j = 0; j < 1000; j++) {
array3[j] = new Rational2(j);
}
for (int k = 0; k < 1000; k++) {
delete array3[k];
}
}
QueryPerformanceCounter(&endTime);
run_time = (((endTime.QuadPart - startTime.QuadPart) * 1000.0) / cpuFreq.QuadPart);
cout << "run_time: "<< run_time <<"ms" << endl;
Rational2::deleteMemPool();
while(1);
}
版本3:单线程可变大小内存管理器
#include <iostream>
#include <windows.h>
static LARGE_INTEGER cpuFreq;
static LARGE_INTEGER startTime;
static LARGE_INTEGER endTime;
static double run_time = 0.0;
using namespace std;
/*需求:当我们一开始无法判断数据所需内存的大小时,需要设计可变大小的内存管理器*/
//MemoryChunk代替前面的NextOnFreeList类,作用:把不同大小的内存块连接成块序列
class MemoryChunk
{
public:
MemoryChunk(MemoryChunk *nextChunk, size_t reqSize);
~MemoryChunk(){delete [] mem;}
inline void *alloc(size_t size);
inline void free(void* someElement){}
//指向列表下一个内存块
MemoryChunk *nextMemoryChunk() {return next;}
//检查当前剩余的内存空间
size_t spaceAvailable() {return chunkSize - byteAlreadyAllocated;}
//默认分配的内存空间
enum {DEFAULT_CHUNK_SIZE = 4096};
private:
MemoryChunk *next;
//要分配的对象
void *mem;
//一个内存块的默认大小
size_t chunkSize;
//当前已经分配的字节数
size_t byteAlreadyAllocated;
};
MemoryChunk::MemoryChunk(MemoryChunk *nextChunk, size_t reqSize)
{
//确认内存块的适当大小
chunkSize = (reqSize > DEFAULT_CHUNK_SIZE)? reqSize :DEFAULT_CHUNK_SIZE;
next = nextChunk;
//这是全新的构造函数,当前已经分配的字节数为0
byteAlreadyAllocated = 0;
//根据内存块的适当大小,分配内存空间
mem = new char[chunkSize];
}
//内存分配请求,返回一个指向mem所指向的MemoryChunk中的可用空间
void* MemoryChunk::alloc(size_t size)
{
void *addr = static_cast<void *>(static_cast<char*>(mem) + byteAlreadyAllocated);
//记录已经分配的内存大小
byteAlreadyAllocated += size;
return addr;
}
class ByteMemoryPool
{
public:
ByteMemoryPool(size_t initSize = MemoryChunk::DEFAULT_CHUNK_SIZE);
~ByteMemoryPool();
inline void *alloc(size_t size);
inline void free(void* someElement) {listOfMemoryChunk->free(someElement);}
private:
//内存块列表
MemoryChunk *listOfMemoryChunk;
//添加内存块
void expandStorage(size_t reqSize);
};
//创建对象,生成私有存储空间
ByteMemoryPool::ByteMemoryPool(size_t initSize)
{
expandStorage(initSize);
}
//释放内存空间
ByteMemoryPool::~ByteMemoryPool()
{
MemoryChunk *memChunk = listOfMemoryChunk;
while (memChunk) {
listOfMemoryChunk = memChunk->nextMemoryChunk();
delete memChunk;
memChunk = listOfMemoryChunk;
}
}
void* ByteMemoryPool::alloc(size_t size)
{
size_t space = listOfMemoryChunk->spaceAvailable();
//所需要的空间大于实践剩余空间,就申请内存
if(space < size){
expandStorage(size);
}
return listOfMemoryChunk->alloc(size);
}
void ByteMemoryPool::expandStorage(size_t reqSize)
{
listOfMemoryChunk = new MemoryChunk(listOfMemoryChunk,reqSize);
}
class Rational3 { //运行时间:20.1893ms
public:
Rational3(int a = 0, int b = 1) : n(a),d(b) {}
inline void* operator new(size_t size){ return memPool->alloc(size); }
inline void operator delete(void* doomed){ return memPool->free(doomed); }
static void newMemPool() { memPool = new ByteMemoryPool; }
static void deleteMemPool(){ delete memPool; }
private:
static ByteMemoryPool* memPool;
static void expandTheFreeList();
enum { EXPANSION_SIZE = 32};
int n; // 分子
int d; // 分母
};
ByteMemoryPool* Rational3::memPool = nullptr;
int main()
{
Rational3 *array3[1000];
Rational3::newMemPool();
QueryPerformanceFrequency(&cpuFreq); //获取系统时钟的频率
QueryPerformanceCounter(&startTime);
for (int i = 0; i < 1000; i++) {
for (int j = 0; j < 1000; j++) {
array3[j] = new Rational3(j);
}
for (int k = 0; k < 1000; k++) {
delete array3[k];
}
}
QueryPerformanceCounter(&endTime);
run_time = (((endTime.QuadPart - startTime.QuadPart) * 1000.0) / cpuFreq.QuadPart);
cout << "run_time: "<< run_time <<"ms" << endl;
Rational3::deleteMemPool();
while(1);
}
增加了分配逻辑的复杂程度,版本3比版本1,2稍慢,但是易用性更高。
3. 要点:
(1). 内存管理器的功能和灵活性增加会降低执行速度。
(2).全局内存管理器的new()和delete()是通用的,代价高。
(3). 专用内存管理器比全局内存管理器快一个数量级以上。
(4). 单线程专用内存管理器省去了全局函数new()和delete()必须要处理并发问题,性能有所提高。理器的功能和灵活性增加会降低执行速度。
(2).全局内存管理器的new()和delete()是通用的,代价高。
(3). 专用内存管理器比全局内存管理器快一个数量级以上。
(4). 单线程专用内存管理器省去了全局函数new()和delete()必须要处理并发问题,性能有所提高。