====== XMemPool ====== **//Inherited from//** NULL **//Inherited by//** NULL **//Friend class//** NULL **//Description//** 常用的malloc/free 和 new/delete 在堆上申请和释放内存都有一定的额外开销。开销来自维护 内存空闲块表。 malloc和new 申请堆内存时,首先查找内部维护的内存空闲块表,并且需要根据一定的算法(例如分配最先找到的不小于申请大小的内存块给请求者,或者分配最适于申请大小的内存块,或者分配最大空闲的内存块等)找到合适大小的空闲内存块。如果该空闲内存块过大,还需要切割成已分配的部分和较小的空闲块。然后系统更新内存空闲块表,完成一次内存分配。 类似地,在free和delete释放内存时,系统把释放的内存块重新加入到空闲内存块表中。如果有可能的话,可以把相邻的空闲块合并成较大的空闲块。默认的内存管理函数还考虑到多线程的应用,需要在每次分配和释放内存时加锁,同样增加了开销。 可见,如果应用程序频繁地在堆上分配和释放内存,则会导致性能的损失。并且会使系统中出现大量的内存碎片,降低内存的利用率。连续的new/delete操作,一大块内存肯能就被分割成小的内存分配出去了,这些小的内存都是不连续的。当再去分配大的连续内存的时候,尽管剩余内存的总和可能大于所要分配的内存大小,但系统就找不到连续的内存了,所以导致分配错误。默认的分配和释放内存算法自然也考虑了性能,然而这些内存管理算法的通用版本为了应付更复杂、更广泛的情况,需要做更多的额外工作。而对于某一个具体的应用程序来说,适合自身特定的内存分配释放模式的自定义内存池则可以获得更好的性能。\\ XT库中XMemPool的类就是一种这样的内存池,它可以通过调用系统的内存分配函数预先一次性申请适当大小的内存作为一个内存池,并为这个内存池类或结构体定义一些分配和释放内存块的成员函数。之后应用程序自己对内存的分配和释放则可以通过这个内存池类及其成员函数来完成。 只有当内存池大小需要动态扩展时,才需要再调用系统的内存分配函数,其他时间对内存的一切操作都在应用程序的掌控之中。\\ 与系统内存管理相比,XMemPool内存池的操作非常迅速,性能优化方面的优点如下:\\ * 针对特殊情况,例如需要频繁分配释放固定大小的内存对象时,不需要复杂的分配算法和多线程/多进程保护(系统内存管理一直会加锁解锁)。也不需要维护内存空闲表的额外开销,只需维护简单的内存池块头信息,从而获得较高的性能。 * 由于开辟一定数量的连续内存空间作为内存池块,因而一定程度上提高了程序局部性和数据访问的速度,提升了程序性能。 * 比较容易控制页边界对齐和内存字节对齐,没有内存碎片的问题。 XMemPool内存池由若干个相同大小的内存片(Chunk)组成,在创建内存池对象时,仅创建一个Chunk,在后面的内存分配中,如果这个Chunk的空间已经用尽,将创建一个新的Chunk并添加到Chunk链表中。Chunk的尺寸是内存池的固有属性,仅可以在构造函数中指定。一个Chunk是一块连续内存,不同Chunk之间不需要连续。从内存池中申请的内存返回内存池之后,该内存成为Chunk的一个内存块(Block),并且根据Block的大小将该内存地址添加到对应的可重分配内存块链表(Reallocatable Block List,RBL)中。RBL存储在第一个Chunk中,增加的Chunk仅在Chunk的头部存储下一个Chunk的首地址。内存池会记录未分配区域的首地址,申请内存时首先从RBL中寻找,如果该链表为空,则从内存池的未分配区域分配。 \\ XT中的内存池有两种使用模式,一种是变长模式,指内存池中有多种长度的Block,申请和返回内存时会根据给定的长度与不小于该长度的最小Block长度取齐;大于最大Block长度(32位操作系统时为4096 Byte)的内存将直接从系统申请或返回给系统。另一种是定长模式,指内存池中只有一种长度的Block,每次分配内存时均按照该Block的长度来分配。为区别于变长模式下的内存块(Block),以后称定长模式下的内存块(Block)为内存单元(Unit)。 **//Members//** * ulong [[mempool#m_ulchunksize|m_ulChunkSize]] * ulong [[mempool#m_ulchunkfreesize|m_ulChunkFreeSize]] * ulong [[mempool#m_ulunitsize|m_ulUnitSize]] * void ** [[mempool#m_prbltable|m_pRBLTable]] * void * [[mempool#m_pfreeheader|m_pFreeHeader]] * LinkNext * [[mempool#m_pchunklist|m_pChunkList]] **//Public interface//** * [[mempool#mempool1|XMemPool]](ulong chunkSize) * [[mempool#mempool2|XMemPool]](ulong unitCnt,ulong unitSize) * void * [[mempool#alloc|alloc]](ulong size) * void * [[mempool#allocunit|allocUnit]]() * void [[mempool#release|release]](void * p,ulong size = 0) * void [[mempool#dumppool|dumpPool]](const char * fname) * void [[mempool#reset|reset]]() * bool [[mempool#isinpool|isInPool]](void * p) **//Private interface//** * [[mempool#mempool3|XMemPool]]([[mempool#mempool3|XMemPool]] &) * void operator [[mempool#copy|=]] (XMemPool&) * void * [[mempool#addchunk|addChunk]]() * void [[mempool#addtorbl|addToRBL]](void * p, ulong size) * void [[mempool#addunittorbl|addUnitToRBL]](void *p) * void * [[mempool#allocfromrbl|allocFromRBL]](ulong size) ---- {{anchor:m_ulchunksize}} **ulong m_ulChunkSize** Chunk大小,XMemPool可以有多个Chunk,单位为字节 {{anchor:m_ulchunkfreesize}} **ulong m_ulChunkFreeSize** 最后一个Chunk里未分配的内存大小,单位为字节 {{anchor:m_ulunitsize}} **ulong m_ulUnitSize** 内存池为定长模式时有效,每个Block的大小,单位为字节 {{anchor:m_prbltable}} **void ** m_pRBLTable** 第一个Chunk的首地址 {{anchor:m_pfreeheader}} **void * m_pFreeHeader** 最后一个Chunk未分配空间的首地址 {{anchor:m_pchunklist}} **LinkNext * m_pChunkList** 存储Chunk首地址的链表 ---- {{anchor:mempool1}} **XMemPool(ulong chunkSize)** *function:在变长模式下构造XMemPool对象 *parameters: - [i]ulong ulSize:chunk的大小,其范围[MIN_CHUNK_SIZE, MAX_CHUNK_SIZE] *return value:无 {{anchor:mempool2}} **XMemPool(ulong unitCnt,ulong unitSize)** *function:在定长模式下构造XMemPool对象 *parameters: - [i]ulong ulUnitCount:每个内存块含有的Block的个数,其范围[1, MAX_CHUNK_SIZE/MIN_BLOCK_SIZE – 2] - [i]ulong ulUnitSize [in]:每个Block所占用的内存大小,其范围[1, MAX_BLOCK_SIZE] *return value:无 {{anchor:alloc}} **void * alloc(ulong size)** *function:变长模式下从池中分配大小为size的内存,定长模式下分配一个unit *parameters: - [i]ulong ulUnitCount:每个内存块含有的Block的个数,其范围[1, MAX_CHUNK_SIZE/MIN_BLOCK_SIZE – 2] *return value:若分配成功则返回分配的内存地址,若失败则返回NULL {{anchor:allocunit}} **void * allocUnit()** *function:从内存池中分配一个unit的内存 *parameters:无 *return value:在变长模式下返回NULL,在定长模式下若成功分配返回unit内存地址,若失败返回NULL {{anchor:release}} **void release(void * p,ulong size = 0)** *function:释放指定的内存,如果该内存是从内存池中申请的,则返回给内存池,添加到相应的RBL中;如果该内存是从系统申请,则返回给系统。 *parameters: - [i]void * p : 需要释放的内存地址 - [i]ulong size : 需要释放的内存大小,取值下限为1 *return value:无 {{anchor:dumppool}} **void dumpPool(const char * fname)** *function:将内存内容写出到名字为fname的文件中 *parameters: - [i]const char * fname:用于dump的文件路径名 *return value:无 {{anchor:reset}} **void reset()** *function:将内存池置于初始状态(仅有一个未分配的Chunk) *parameters:无 *return value:无 {{anchor:isinpool}} **bool isInPool(void * p)** *function:判断指定地址是否在内存池中 *parameters: - [i]void * p : 需要判断的内存地址 *return value:若在内存池中返回true,否则返回false ---- {{anchor:mempool3}} **XMemPool(XMemPool &)** *function:禁止复制构造 *parameters: - [i]XMemPool &:另外一个XMemPool的引用 *return value:无 {{anchor:copy}} **void operator = (XMemPool &)** *function:禁止拷贝构造 *parameters: - [i]XMemPool &:另外一个XMemPool的引用 *return value:无 {{anchor:addchunk}} **void * addChunk()** *function:从系统中申请一个chunk添加到内存池中 *parameters:无 *return value:若申请成功则返回该chunk的地址,否则返回NULL {{anchor:addtorbl}} **void addToRBL(void * p, ulong size)** *function:在变长模式下将大小为size的内存p放入到内存池RBL中 *parameters: - [i]void * p : 需要放回的内存 - [i]ulong ulSize : 放回的内存大小 *return value:无 {{anchor:addunittorbl}} **void addUnitToRBL(void *p)** *function:在定长模式下将内存p放入到内存池RBL中 *parameters: - [i]void * p : 需要放回的Unit *return value:无 {{anchor:allocfromrbl}} **void * allocFromRBL(ulong size)** *function:在变长模式下从内存池的RBL中分配大小为ulSize的内存 *parameters: - [i]ulong ulSize : 需要分配的内存大小 *return value:若在可重分配内存块中找到匹配的Block则返回该Block的内存地址,否则返回NULL