读书人

哪位高手有高效的内存池提供原理或者

发布时间: 2012-03-02 14:40:28 作者: rapoo

谁有高效的内存池,提供原理或者实现都可以,非常感谢
我自己开发一个分布式FTP服务软件[ftpanywhere],开发完成后通过对比,发现标准库或者STL或者MFC库的数据或者容器,在开发客户端时问题不大,但是我把它用在服务器端的数据结构中后,存在效率问题,而这些效率问题,无论是标准库或者STL或者MFC的书籍以及代码中,很少有人提及,也没有找到合理的解决方法,
例如:
我们经常需要在数据结构中保留一个或者几个std::string或者CString或者其他类似的字符串,可实际上这东西是杀手,效率很低,尽管有什么引用记数,但是服务器中的数据量一大,如果没有有效的内存分配机制,几乎是杀手级别的东西,而且你还找不出原因,类似的还有vector <something> ,CArray <something> ,......最不可想象的就是vector <string> 或者CStringArray这样的类了。。。。。。太多太多,有兴趣各位可以自己去做个频繁调用分配释放实验。

现在我自己根据需要实现了一个类似操作系统方式的内存池,效率大概是这样的,
内存分配速度,大约是 标准NEW操作(或者MALLOC)的2倍到7倍,但是在极限情况下也可能出现N倍于NEW的情况[只出现一次,下次会自动识别并跳转],释放操作大约是0,而DELETE(FREE)操作的速度大约是NEW操作的10倍以上,采用了平坦模式,据我所知,大型商业数据库如ORACLE以及微软的WEB服务器IIS也采用了和我同样原理的内存池模式,但是不确定,原理是一次申请大块内存,然后根据需要分配,用完再申请一大块,全进程只需要一个就可以,当然也可以有几个,满足不同需要,粒度是可以调节的。
我在网络上检索内存池技术和实现,包括了BOOST:POOL的实现[个人觉得针对非常小的数据例如INT等比较好,但是用局部堆实现这些小数据不更加好?释放依然是个问题],CODEPROJECT上内存池的实现,以及那个叫什么SMMP的服务模式的内存池实现,普遍采用了内存块指针模式,这个其实我认为都是有问题的,都会导致操作系统级的内存碎片化,它只是避免了进程内部已经分配的内存碎片化,而且在分配速度上,当内存数据一多,效率明显低于我的内存池实现。 特别是在退出时,因为还是需要涉及到大量释放问题。
在我确定采用我自己的内存池技术前,想请教各位,有没有其他的实现模式?
原理就可以了,有点代码当然更好
谢谢各位

[解决办法]
俺mark,俺觉得LS的思路不错。
另:free时,俺觉得应该在p指针前,保留指针的长度或对应Owner分配对象,这样,直接取出free,而不需要判断,我觉得会快些。
[解决办法]
还有个问题,如果是WINDOWS,有些IO操作是需要将内存块锁定的,这时就不能用这样分配方法,比如是一个大块[X]分出来的一个小块[X.A]需要LOCK,这时成功,但下次分出[X.B]再想Lock会失败,所以。。。
这个楼主要具体试下,好像俺是遇到过。
[解决办法]
貌似free还有个问题,就是同一内存块,调用free多次。。。
[解决办法]
to ERR0RC0DE():

> > > p指针前,保留指针的长度或对应Owner分配对象...

这些方法我也考虑过,但这样一个 4 byte 的 length 或 Owner* 比较占空间。
现在 uint32 m_map[block_cnt],一个 每 block = 256 byte 的 pool,光是 m_map 就占了 4/256=1/64
我程序中只开 2M 左右的 pool,其中 m_map 就占了 32K,甚是浪费

> > > 如果是WINDOWS,有些IO操作是需要将内存块锁定的...

win32 下 lock 的问题,我倒还没关注到,因为代码主要是用在一个 uClinux 下单线程的程序中

> > > 同一内存块,调用free多次。。。

如果是人为不小心的,那就是程序员的问题了,呵呵...

[解决办法]
to danscort2000(danscort.yu):

事实上,我上面的内存池不是为了加快速度而设计的,也不是在多线程环境下使用,所以性能和安全性可能不适合一般用途

我正在业余写一个嵌入式的 BT 客户端,uCLinux OS/无 MMU,只允许使用 4M 内存,为避免从全局堆动态分配内存,就写了这么一个简单的 mem pool,目的就是一次性分配好内存再拿来用,效率等等就暂时没怎么考虑,从目前设备上运行的效果来看,如果运算上有消耗,但没影响到下载速度

使用重载 new/delete 的方式呢,一个是方便简化操作,跟平常一样 new/delete 一个对象就行,另外是方便去掉 #define USE_MEMPOOL 后,也就去掉了自己的 mem pool


[解决办法]
俺顶
有没有说说(free时)碎片处理这方面的处理,俺觉得那处理特烦。
[解决办法]
Loki也有内存管理技术,貌似比boost::pool更好,如果要自己写内存管理,《提高C++性能的编程技术》一书中有一张的讲解。
[解决办法]
回来再说一下我的内存池的改动:

uint32 m_map[CNT];

这里我改成了用一个 byte (uint8) 来表示

如果只分一块,则 m_map[i] = 'I ', 如果连续分出 3 - 12 块,则 m_map[2] = '[ ', m_map[11] = '] ',从而节省了 3/4 的 m_map 空间

每个 m_map[i] 其实就 4 种状态(0, 'I ', '[ ', '] '),理论上可用 2 bit 来表示,但要衡量位操作所带来的运算损耗是否值得,这点我没细测

这是偶尔才想起的改进,告知大家,以便有类似情况时大家能应用上

[解决办法]
缺省的new/delete从堆上分配和释放。
次数多了会有碎片影响效率。
自己做可以重载缺省的new/delete,
一般初始化分配一大的内存块表,如128字节和64字节2个练表,
申请和释放都在在这个表中进行。

参考一下apache的内存池,
[解决办法]
双核的时候,根本就不是用这些普通的并发机制就够的。
singleton实现讨论过无数次,必须3次lock_check加锁总线指令。


多核编程,需要完全不同的编程技能了,否则多核只会比单核更慢。
herb sutter的 "免费午餐已经结束 "就讲的这个话题。
所以,我能给的建议就是不要让一个进程同时跑在2个核上。

读书人网 >C++

热点推荐