Herm的Allocator介绍

Allocator可以理解特定对象池。Herm目前有两种Allocator,LiteAllocator和LargeAllocator,前者支持小于120bytes的小对象;后者支持大对象,建议大于120byte以上的对象使用LargeAllocator,小对象当然也支持,但会浪费内存,每个对象将附加8bytes的内存空间。STL也可以直接用Herm的Allocator作为Allocator。


LiteAllocator 在Linux其实就是__gnu_cxx::pool_alloc, Windows上直接弄成std::allocator,因为Herm的定位是开发Linux&FreeBSD的服务器,Windows建议就做客户端。

下面介绍一下LargeAllocator的实现原理。

LargeAllocator内部以Chunk为单位从系统申请内存,默认大小是4K。所有的Chunk形成一个单向链表。

一个Chunk分成X个Block,Block内部有对象的空间。未用的Block形成一个可用的Block单向链表。已用的Block形成一个已用的Block双向链表。由于这个Allocator本身的出发点是支持大对象(>128bytes),所有对链表的生成没做任何优化措施,保证代码简单性。这样会浪费额外的8bytes空间,最大浪费率是:8 / 128 = 6.25%,应该在接受范围内。

下面是Block&Chunk的结构。

struct Block
{
	T obj;
	Block* pre;  
	Block* next;
};

struct Chunk
{
	Chunk* next;
	char buf[1];
};

LargerAllocator维护:

1. Chunk的单向链表(ChunkList)

2.  空闲的Block单向链表(FreeBlockList)

3. 已用的Block单向链表(UsedBlockDeList)


分配一个对象空间

从FreeBlockList取一个Block,把Block内部的T空间返回给调用者。

如果FreeBlockList没有Block了,就要从系统分配一个Chunk,把Chunk加入到ChunkList,同时把Chunk分成X个Block,并把这些Block加入到FreeBlockList中。


释放一个对象空间

其实就是释放一个Block。

从UsedBlockDeList里把对应的Block拿掉,UseBlockDeList是双向链表,拿的动作是O(1)。

将Block放回FreeBlockList的头部。

虑内存访问的效率,链表插入和取出操作都在表头进行。所有的动作都是O(1)。


LargeAllocator的析构

把UsedBlocks归还给FreeBlocks? 归还的过程将调用具体对象的析构函数。
这一步也可以不用归还,就直接在UsedBlocks调用一下具体对象的析构函数,省了O(1)的插入过程。

扫描Chunk链表,把每个Chunk delete掉,内存还给了系统。



posted on 2011-09-08 16:58  daemonh  阅读(171)  评论(0编辑  收藏  举报

导航