暴米花 发表于 2006-12-11 11:33:00

一个快速的内存分配池

<strong><br/><br/></strong>对于现代的游戏引擎来说,为了提高性能和有效的管理内存,需要使用各种各样<br/>的内存分配模型,内存池作为一种有效的分配模型被大量的使用,它通过一次分配<br/>足够的内存来减少对new&nbsp;delelte使用以提高引擎的性能,并且由于每一个内存块<br/>都有相同的大小因此非常易于管理,并可以防止内存的泄露。它通常被用于需要<br/>分配大量相同对象的场合,如粒子系统这样的地方。 <p></p><p>对于在运行时可以明确知道分配数量的物体,可以通过一个静态数组来实现它,<br/>但对于不知道分配数量的地方,设计就变的有些复杂,通常需要使用一个链表来<br/>进行实现,如STL的list容器,不过使用它有一个很大的缺点,链表对表中的对象<br/>进行查询操作时速度不是很理想,会极大影响它的性能。因此需要寻找一个比较<br/>好的方法对其进行改进。</p><p>通常设计内存池有两个问题必须考虑,一个是内存分配的策略,由于你不是明确<br/>知道待分配物体的数量,因此每次分配多大数量的内存是一个值得注意的问题。<br/>另一个是如何对内存池进行管理,使用什么样的数据结构才能在常数时间内来获得<br/>指定的内存。对于第一个问题解决的方案很多,你可以每次都分配一个指定数量<br/>的内存块,也可以在每次分配时都分配比上一次多一倍的内存,哪种方案更好,需要<br/>你自己在实际使用中体会。第二个问题是本文的核心,一般的做法是将已经分配的<br/>内存块分成两个部分,已使用和未使用两个链表,但是这样做的性能并不理想,下面<br/>看看如何对其进行改进:</p><p>我们先建立一个结构用于保存每次分配的一整块内存:<br/>sturct&nbsp;MemChunk<br/>{<br/>&nbsp;&nbsp;MemChunk*&nbsp;m_pPre;<br/>&nbsp;&nbsp;MemChunk*&nbsp;m_pNext;<br/>&nbsp;&nbsp;unsigned&nbsp;int&nbsp;m_nSize;<br/>&nbsp;&nbsp;char&nbsp;m_Data;<br/>}<br/>在这个结构中m_pPre,m_pNext用于建立一个双向链表将每一次分配的内存连接起来,<br/>m_nSize表示当前内存块的大小,m_Data是所分配的内存指针,必须注意这是一个BYTE<br/>指针。我们现在假设当前的内存池用于对CObject物体分配内存,每次分配都一次分配<br/>64个CObject物体的内存,因此m_nSize的大小为64*sizeof(CObject)。下面看看如何<br/>保存未使用的内存块,我们需要一个指针来指向当前未使用的内存块。<br/>void*&nbsp;s_pCurrent;<br/>然后令它指向当前还未使用的内存块。<br/>s_pCurrent&nbsp;=&nbsp;pMemChunk-&gt;mData;<br/>下面是本文最关键的部分,为了提高性能我们令每一个未使用的内存块的头部都保存<br/>一个指针,让它指向下一个未使用的内存块,这样就为未使用的内存块形成了一个单<br/>向链表。当你需要一个物体的内存时可以这么做:<br/>void*&nbsp;returnPtr&nbsp;=&nbsp;s_pCurrent;<br/>s_pCurrent&nbsp;=&nbsp;*((void&nbsp;**)s_pCurrent);<br/>return&nbsp;returnPtr;<br/>这样returnPtr就是你要获得的内存指针,而s_pCurrent通过一个简单的指针转换巧妙<br/>的又指向了下一个内存块,如果上一句看不懂,请你重新复习一下C++教材中关于指针<br/>的解释。<br/>当你需要释放一个物体的内存时,方法和此类似。<br/>*((void**)pMem&nbsp;=&nbsp;s_pCurrent;<br/>s_pCurrent&nbsp;=&nbsp;pMem;<br/>这样就可以将内存块重新连接到未使用的内存块链表中。通常对指针进行转换的时间<br/>非常短,比一般的链表的插入、删除操作速度快的多,因此这个技巧是非常值得借鉴<br/>的做法。</p>
页: [1]
查看完整版本: 一个快速的内存分配池