【内存池系列】提高C++性能的编程技术 学习笔记(二) 内存池
2012-03-13 19:50
417 查看
内存池
内存池(Memory Pool)是一种内存分配方式。 通常我们习惯直接使用new、malloc等API申请分配内存,这样做的缺点在于:由于所申请内存块的大小不定,当频繁使用时会造成大量的内存碎片并进而降低性能。内存池则是在真正使用内存之前,先申请分配一定数量的、大小相等(一般情况下)的内存块留作备用。当有新的内存需求时,就从内存池中分出一部分内存块,若内存块不够再继续申请新的内存。这样做的一个显著优点是尽量避免了内存碎片,使得内存分配效率得到提升。
以下是两种不同结构的内存池实现方法。
链式结构:
通过模板实现,使得多个类可以使用,无需重写。创建MemoryPool对象时,为模板的类对象获得大小为EXPANSION_SIZE(32)块的内存,每块的字节数为sizeof(T)。当需要使用时,调用alloc函数,将next指向的空内存块分配,释放对象时,调用free函数将内存块还给链表,添加到空闲链表头。
可变大小的内存管理器:
使用内存池能够极大提高内存的使用效率和程序的执行效率。笔者在不使用内存池和使用以上两个不同版本的内存池的情况分别对程序的执行时间进行了测试;
测试代码如下:
不使用内存池,直接使用new和delete管理内存的情况下,以上程序执行耗时426ms,使用版本一内存池耗时99ms,版本二内存池耗时216ms。不难看出,使用内存池能够极大提高执行效率,同时不会产生外部内存碎片。版本二内存池相较版本一内存池虽然较慢,但增加了分配逻辑的复杂性,同时更加强大。
还有一篇更好的文章,讲的非常清楚,链接:/article/8706629.html
内存池(Memory Pool)是一种内存分配方式。 通常我们习惯直接使用new、malloc等API申请分配内存,这样做的缺点在于:由于所申请内存块的大小不定,当频繁使用时会造成大量的内存碎片并进而降低性能。内存池则是在真正使用内存之前,先申请分配一定数量的、大小相等(一般情况下)的内存块留作备用。当有新的内存需求时,就从内存池中分出一部分内存块,若内存块不够再继续申请新的内存。这样做的一个显著优点是尽量避免了内存碎片,使得内存分配效率得到提升。
以下是两种不同结构的内存池实现方法。
链式结构:
通过模板实现,使得多个类可以使用,无需重写。创建MemoryPool对象时,为模板的类对象获得大小为EXPANSION_SIZE(32)块的内存,每块的字节数为sizeof(T)。当需要使用时,调用alloc函数,将next指向的空内存块分配,释放对象时,调用free函数将内存块还给链表,添加到空闲链表头。
#ifndef _MEM_POOL_ #define _MEM_POOL_ template<class T> class MemoryPool { public: MemoryPool(size_t size = EXPANSION_SIZE); ~MemoryPool(); inline void* alloc(size_t size); inline void free(void *someElement); private: MemoryPool<T>* next; enum{EXPANSION_SIZE =32}; void expandTheFreeList(int howMany=EXPANSION_SIZE); }; template<class T> MemoryPool<T>::MemoryPool(size_t size /* = EXPANSION_SIZE */) { expandTheFreeList(size); } template<class T> MemoryPool<T>::~MemoryPool() { MemoryPool<T> *nextPtr=next; for(nextPtr=next;nextPtr!=NULL;nextPtr=next) next=next->next; delete [] nextPtr; } template<class T> inline void* MemoryPool<T>::alloc(size_t size) { if(!next) expandTheFreeList(); MemoryPool<T> *head = next; next=head->next; return head; } template <class T> inline void MemoryPool<T>::free(void *doomed) { MemoryPool<T> *head=(MemoryPool<T>*)doomed; head->next=next; next=head; } template<class T> void MemoryPool<T>::expandTheFreeList(int howMany/* =EXPANSION_SIZE */) { size_t size=(sizeof(T)>sizeof(MemoryPool<T>*))? sizeof(T):sizeof(MemoryPool<T>*); MemoryPool<T>* runner=(MemoryPool<T>*)new char[size]; next=runner; for(int i=0;i<howMany;i++){ runner->next=(MemoryPool<T>*)new char[size]; runner=runner->next; } runner->next=0; } #endif
可变大小的内存管理器:
#ifndef _MEM_CHUNK_ #define _MEM_CHUNK_ class MemoryChunk { private: MemoryChunk *next; void *mem; size_t chunkSize; //一个内存块的默认大小 size_t bytesAlreadyAllocated; //当前内存块中已分配的字节数 public: MemoryChunk(MemoryChunk *nextChunk,size_t chunkSize); ~MemoryChunk(); inline void *alloc(size_t size); inline void free(void* someElement); //指向列表下一内存块的指针 MemoryChunk *nextMemChunk() {return next;} //当前内存块剩余空间大小 size_t spaceAvailable() {return chunkSize-bytesAlreadyAllocated;} enum{DEFAULT_CHUNK_SIZE=4096}; }; inline void* MemoryChunk::alloc(size_t requestSize) { void* addr=(void*)((size_t)mem+bytesAlreadyAllocated); bytesAlreadyAllocated+=requestSize; return addr; } inline void MemoryChunk::free(void* doomed) {} #endif
#include "stdafx.h" #include "MemoryChunk.h" MemoryChunk::MemoryChunk(MemoryChunk *nextChunk,size_t reqSize) { chunkSize=(reqSize>DEFAULT_CHUNK_SIZE)? reqSize:DEFAULT_CHUNK_SIZE; next=nextChunk; bytesAlreadyAllocated=0; mem=new char[chunkSize]; } MemoryChunk::~MemoryChunk() { delete [] mem; }
#ifndef _BYTE_MEM_POOL_ #define _BYTE_MEM_POOL_ #include "MemoryChunk.h" class ByteMemoryPool { private: //内存块列表 MemoryChunk *listofMemoryChunks; //向内存块列表添加一个内存块 void expandStorage(size_t reqSize); public: ByteMemoryPool(size_t initSize=MemoryChunk::DEFAULT_CHUNK_SIZE); ~ByteMemoryPool(); //从私有内存池分配内存 inline void *alloc(size_t requestSize){ size_t space=listofMemoryChunks->spaceAvailable(); if(space<requestSize) { expandStorage(requestSize); } return listofMemoryChunks->alloc(requestSize); } //释放先前从内存池中分配的内存 inline void free(void* doomed) { listofMemoryChunks->free(doomed); } }; #endif
#include "stdafx.h" #include "ByteMemoryPool.h" ByteMemoryPool::ByteMemoryPool(size_t initSize):listofMemoryChunks(0) { expandStorage(initSize); } ByteMemoryPool::~ByteMemoryPool() { MemoryChunk *memChunk=listofMemoryChunks; while(memChunk){ listofMemoryChunks=memChunk->nextMemChunk(); delete memChunk; memChunk=listofMemoryChunks; } } void ByteMemoryPool::expandStorage(size_t reqSize) { listofMemoryChunks=new MemoryChunk(listofMemoryChunks,reqSize); }
使用内存池能够极大提高内存的使用效率和程序的执行效率。笔者在不使用内存池和使用以上两个不同版本的内存池的情况分别对程序的执行时间进行了测试;
测试代码如下:
// SimpleAlloc.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <iostream> #include <ctime> using namespace std; class Rational{ private: int n; int d; public: Rational(int a=0,int b=1):n(a),d(b){} }; int _tmain(int argc, _TCHAR* argv[]) { size_t start,end; Rational *array[1000]; start=clock(); for(int j=0;j<500;j++){ for(int i=0;i<1000;i++){ array[i]=new Rational(i); } for(int i=0;i<1000;i++) delete array[i]; } end=clock(); cout<<end-start; return 0; }
不使用内存池,直接使用new和delete管理内存的情况下,以上程序执行耗时426ms,使用版本一内存池耗时99ms,版本二内存池耗时216ms。不难看出,使用内存池能够极大提高执行效率,同时不会产生外部内存碎片。版本二内存池相较版本一内存池虽然较慢,但增加了分配逻辑的复杂性,同时更加强大。
还有一篇更好的文章,讲的非常清楚,链接:/article/8706629.html
相关文章推荐
- 提高c++性能的编程技术笔记
- 【编程语言】提高C++性能的编程技术 笔记(一)
- 提高C++性能编程学习之内存池技术(一)
- Java系列学习笔记------Java技术基础<1>
- 黑马程序员——Objective-C程序设计(第4版)学习笔记之02-Objective-C 编程环境概述——黑马 IOS 技术博客
- Java TCP/IP Socket 编程学习笔记系列 +数据结构
- 《Java 多线程编程核心技术》学习笔记及总结
- 改善C++ 程序的150个建议学习之建议35:使用内存池技术提高内存申请效率与性能
- struts2系列学习笔记(9)---------------编程方式的验证
- 【提高C++性能的编程技术】读书笔记1 -- 导言
- 读书笔记:提高C++性能的编程技术
- 程序员编程技术学习笔记——字符串包含
- 程序员编程技术学习笔记——最长回文子串
- 【技术门诊128期】从C/C++学习谈编程能力的培养与提高!
- java系列:《java核心技术 卷1》学习笔记,chapter 11 调试技巧
- 程序员编程技术学习笔记
- 【提高C++性能的编程技术】读书笔记2 -- 跟踪实例
- 【C++】学习笔记草稿版系列3(引用基础与提高)
- c++单线程可变大小内存管理器代码 from 提高c++性能的编程技术
- 《Java多线程编程核心技术》学习笔记-第一章