荔园在线
荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀
[回到开始]
[上一篇][下一篇]
发信人: mmkiller (8楼电梯里的6个傻男人), 信区: Program
标 题: Memory Pool 技术
发信站: 荔园晨风BBS站 (2005年11月02日23:18:01 星期三), 站内信件
http://www.blog.edu.cn/user2/55120/archives/2005/351841.shtml#183165
C++内存池实现(1)前言
本文是“C++内存池实现”的第一部分,本文内容来自《提高C++性能的编程技术》,我只
是对里面的内容进行了整理,并对一些晦涩的地方进行了解释。
对原书中的一些代码进行了调整,使之在VS.NET 2003的环境下调试通过。
全局函数new()和delete()
C++默认的new()和delete()方式是通用的内存管理方式,可以通过此分配和释放大
小不同的内存,在多线程的环境中,提供了对内存分配和释放的并发保护,但是这些灵活
性是以牺牲性能、程序的执行速度为代价的。让我们看一个例子:
首先是我们要操作的有理数类的定义rational.h:
//
// rational.h – definition of the rational class
// wangzhi 2005-10-25
//
#ifndef _RATIONAL_H
#define _RATIONAL_H
class Rational
{
public:
Rational ( int a = 0, int b= 1 ) : n (a), d(b) {}
private:
int n; // Numerator
int d; // Denominator
};
#endif // _RATIONAL_H
接下来是测试程序的代码test1.cpp:
//
// test1.cpp – test the global new() and delete() functions’ performance
// wangzhi 2005-10-25
//
#i nclude <windows.h>
#i nclude <stdio.h>
#i nclude "rational.h"
int main()
{
Rational *array[1000];
// Start timing here
DWORD last, current;
last = GetTickCount();
for (int j = 0; j < 500; j ++)
{
for (int i = 0; i < 1000; i ++)
array[i] = new Rational(i);
for (i = 0; i < 1000; i ++)
delete array[i];
}
// Stop timing here
current = GetTickCount();
printf("Time cost: %d", current - last);
getchar();
}
程序的运行结果是:
Time cost: 7281ms
专用Rational内存管理器
在大多数的C++程序中,我们可能只需要分配和释放一些大小固定的内存空间,而且程序可
能只会在单线程的环境中运行,因此如果此时使用功能强大的new()和delete()就会导致很
大的性能开销,在此我们实现一个上述定义的Rational类的对象静态链表,这个静态列表
将作为一个可用对象的空闲列表,需要Rational对象时就从空闲列表中取出一个,对象操
作完毕后,再将它放回空闲列表中。如图1示:
图1 Rational对象的空闲列表
接下来看看头文件rational1.h的定义:
//
// rational1.h - definition of the NextOnFreeList and rational class
// wangzhi 2005-10-25
//
#ifndef _RATIONAL1_H
#define _RATIONAL1_H
class NextOnFreeList
{
public:
NextOnFreeList *next;
};
class Rational
{
public:
Rational (int a = 0, int b = 1) : n(a), d(b) {}
inline void *operator new (size_t size);
inline void operator delete (void *doomed, size_t size);
static void newMemPool() { expandTheFreeList(); }
static void deleteMemPool();
private:
static NextOnFreeList *freeList;
static void expandTheFreeList();
enum { EXPANSION_SIZE = 32 };
int n;
int d;
};
#endif // _RATIONAL1_H
在rational1.h中首先定义了一个辅助类NextOnFreeList用以链接不同的Rational对象
,需要注意的是,空闲列表的每一个元素既是NextOnFreeList对象,又是Rational对象,
每个Ratioanl对象的头几个字节是一个NextOnFreeList指针,指向空闲列表中下一个Ratio
nal对象。
现在来看一下专用Rational内存池的实现rational1.cpp:
//
// rational1.cpp – implement the Rational specific memory pool
// wangzhi 2005-10-25
//
#i nclude "rational1.h"
void *Rational::operator new (size_t size)
{
if (0 == freeList)
expandTheFreeList();
NextOnFreeList *head = freeList;
freeList = head->next;
return head;
}
void Rational::operator delete (void *doomed, size_t size)
{
NextOnFreeList *head = static_cast<NextOnFreeList *> (doomed);
head->next = freeList;
freeList = head;
}
void Rational::expandTheFreeList()
{
size_t size = (sizeof (Rational) > sizeof (NextOnFreeList *)) ?
sizeof (Rational) : sizeof (NextOnFreeList *);
NextOnFreeList *runner = reinterpret_cast<NextOnFreeList *>
(new char[size]);
freeList = runner;
for (int i = 0; i < EXPANSION_SIZE; i ++ )
{
runner->next = reinterpret_cast<NextOnFreeList *> (new char[size]);
runner = runner->next;
}
runner->next = 0;
}
void Rational::deleteMemPool()
{
NextOnFreeList *nextPtr;
for ( nextPtr = freeList; nextPtr != 0; nextPtr = freeList )
{
freeList = freeList->next;
delete[] nextPtr;
}
}
程序首先重载了new()和delete()以实现Rational类特有的内存管理方式,new()从空
闲列表中分配一个新的Rational对象,如果列表为空,则扩展它,在这里是从列表的头部
取一个新对象返回,然后将空闲列表头部指针freeList后移。delete()将一个使用过的Rat
ional对象返回空闲列表,将它插入空闲列表的头部,此时的freeList指针将指向它。
当需要分配一个新对象,而空闲列表已使用完时,需要调用expandTheFreeList()从堆
中分配更多的Rational对象以备用。这里先说明下一个要点,就是当分配一个对象内存时
,该对象内存的头几个字节被强制转换为NextOnFreeList*类型,以便插入到空闲列表中,
当程序使用new()将该对象内存从空闲列表取出时,原来NextOnFreeList*指针占有的空间
将被使用,当程序使用完此对象并用delete()将其返回空闲列表时,对象的头几个字节又
被转换为NextOnFreeList*指针类型,然后对象链接入空闲列表中,在expandTheFreeList(
)中,由于一个对象内存需要包含NextOnFreeList*指针和Rational对象,所以需要分配一
个足够大的内存空间,然后将此内存空间的开始几个字节强制转换为NextOnFreeList*类型
,并使freeList指向此内存空间,然后依次分配EXPANSION_SIZE个对象内存。
deleteMemPool()用于释放整个内存池,该函数遍历整个空闲列表,删除每个对象内存
空间,注意在分配内存时使用了new char[size],因此在删除时就要使用delete[]
nextPtr。
下面是测试程序test2.cpp:
//
// test2.cpp – test the Rational specific memory pool’s performance
// wangzhi 2005-10-25
//
#i nclude <windows.h>
#i nclude <stdio.h>
#i nclude "rational1.h"
NextOnFreeList *Rational::freeList = 0;
int main()
{
Rational *array[1000];
Rational::newMemPool();
// Start timing here
DWORD last, current;
last = GetTickCount();
for (int j = 0; j < 500; j ++)
{
for (int i = 0; i < 1000; i ++)
array[i] = new Rational(i);
for (i = 0; i < 1000; i ++)
delete array[i];
}
// Stop timing here
current = GetTickCount();
Rational::deleteMemPool();
printf("Time cost: %d", current - last);
getchar();
}
程序的输出结果是:
Time cost: 109ms
结论
对1000个Rational对象进行500次的分配和释放,结果表明,使用全局的new()和delete()
耗时7281ms,而专用Rational内存管理器只耗时109ms,比前者快了近67倍。
全局函数new()和delete()是通用的内存管理方式,其灵活并能在多线程环境中控制并发,
但是也因此付出了性能的代价,一个特定的C++程序可以使用特定的内存管理方式来实现内
存的分配和释放,而不需要为不必要的考虑付出代价。
参考书目
《提高C++性能的编程技术》(Efficient C++ Performance Programming Techniques)
Dov Bulka, David Mayhew, Addison Wesley 2002
--
*[0;3*┌─╮˙ ╭ ╭╮╭╭─╮╭┬╮*BigcatNAT 透明代理 功能*
*├─┤│╭─╮╭─ ╭─╮-┼-│││├─┤ │ *自 动 过 滤 收 费 连 接*
*└─╯│╰─│╰─╯╰─╰ ╰ ╰╰╯╰ ╯ ╰ *简 化 软 件 代 理 设 置*
*╰─╯ *0 5 年 3 月 最 新 2 . 0 测 试 版 发 布*
* *详 细 功 能 说 明 及 软 件 下 载 , 请 连 接 至 下 面 的 地 址 *
*http://www.flashszu.com/BigcatNAT* *Powered by BiGcAt.NET *
※ 修改:·mmkiller 於 11月02日23:20:52 修改本文·[FROM: 192.168.110.120]
※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.110.120]
[回到开始]
[上一篇][下一篇]
荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店