linux boost内存池,内存池溢出的原理与解决方法 - 开源C++函数库Boost内存池使用与测试_Linux编程_Linux公社-Linux系统门户网站...

内存池在底层也是调用了malloc函数,因此内存池也是必然会溢出的。而且内存池可能会比直接调用malloc更早的溢出,看看下面的代码:

18b4619886cc50d89481a2c35f1169fb.gif#include"stdafx.h"18b4619886cc50d89481a2c35f1169fb.gif#include18b4619886cc50d89481a2c35f1169fb.gif#include18b4619886cc50d89481a2c35f1169fb.gif#include18b4619886cc50d89481a2c35f1169fb.gif#include18b4619886cc50d89481a2c35f1169fb.gif#include18b4619886cc50d89481a2c35f1169fb.gifusingnamespacestd;

18b4619886cc50d89481a2c35f1169fb.gifusingnamespaceboost;

18b4619886cc50d89481a2c35f1169fb.gif

18b4619886cc50d89481a2c35f1169fb.gifint_tmain(intargc, _TCHAR*argv[])

724f579eb847bf91dff20d82e6a32e8d.gif

d01baf9b287f1a06d082be5253e99a31.gif...{

788fd394a7cc1f5c037b1b94251c9f3e.gif    boost::pool<>pl(1024*1024);

788fd394a7cc1f5c037b1b94251c9f3e.gif    clock_t clock_begin=clock();

788fd394a7cc1f5c037b1b94251c9f3e.gifintiLength=0;

788fd394a7cc1f5c037b1b94251c9f3e.giffor(inti=0; ;++i)

89f7845f3a81fcad79662ab95b5c9b78.gif

b7680ae2c4e52ef448f5e5d309cb2c79.gif...{

788fd394a7cc1f5c037b1b94251c9f3e.gifvoid*p=pl.malloc();

788fd394a7cc1f5c037b1b94251c9f3e.gifif(p==NULL)

89f7845f3a81fcad79662ab95b5c9b78.gif

b7680ae2c4e52ef448f5e5d309cb2c79.gif...{

788fd394a7cc1f5c037b1b94251c9f3e.gifbreak;

1eb7de1d4600772660d7948d0ed9ef7c.gif        }788fd394a7cc1f5c037b1b94251c9f3e.gif++iLength;

1eb7de1d4600772660d7948d0ed9ef7c.gif    }788fd394a7cc1f5c037b1b94251c9f3e.gif    clock_t clock_end=clock();

788fd394a7cc1f5c037b1b94251c9f3e.gif    cout<

788fd394a7cc1f5c037b1b94251c9f3e.gifreturn0;

288f2f2748ca34b6348bbced16902be5.gif}

运行的结果是“共申请了992M内存,程序运行了 1265 个系统时钟”,意思是在分配了992M内存后,内存池已经不能够申请到1M大小的内存块了。

5.2 内存池的基本原理

从上面的两个测试可以看出内存池要比malloc溢出早,我的机器内存是1.5G,malloc分配了1916M才溢出(显然分配了虚拟��存),而内存池只分配了992M就溢出了。第二点是内存池溢出快,只用了1265微秒就溢出了,而malloc用了69421微秒才溢出。

这些差别是内存池的处理机制造成的,内存池对于内存分配的算法如下,以pool内存池为例:

1. pool初始化时带有一个块大小的参数memSize,那么pool刚开始会申请一大块内存,例如其大小为32*memSize。当然它还会申请一些空间用以管理链表,为方便述说,这里忽略这些内存。

2. 用户不停的申请大小为memSize的内存,终于超过了内存池的大小,于是内存池启动重分配机制;

3. 重分配机制会再申请一块大小为原内存池大小两倍的内存(那么第一次会申请64*memSize),然后将这块内存加到内存池的管理链表末尾;

4. 用户继续申请内存,终于又一次超过了内存池的大小,于是又一次启动重分配机制,直至重分配时无法申请到新的内存块。

5. 由于每次都是两倍于原内存,因此当内存池大小达到了992M时,再一次申请就需要1984M,但是malloc最多只能申请到1916M,因此malloc失败,内存池溢出。

通过以上原理也可以理解为什么内存池溢出比malloc溢出要快得多,因为它是以2的指数级来扩大内存池,真正调用malloc的次数约等于log2(1916),而malloc是实实在在进行了1916次调用。所以内存池只用了1秒多就溢出了,而malloc用了69秒。

5.3 内存池溢出的解决方法

对于malloc造成的内存溢出,一般来说没有太多办法可想。基本上就是报一个异常或者错误,然后让用户关闭程序。当然有的程序会有内存自我管理功能,可以让用户选择关闭一切次要功能来维持主要功能的继续运行。

而对于内存池的溢出,还是可以想一些办法的,因为毕竟系统内存还有潜力可挖。

第一个方法是尽量延缓内存池的溢出,做法是在程序启动时就尽量申请最大的内存池,如果在程序运行很久后再申请,可能OS因为内存碎片增多而不能提供最大的内存池。其方法是在程序启动时就不停的申请内存直到内存池溢出,然后清空内存池并开始正常工作。由于内存池并不会自动减小,所以这样可以一直维持内存池保持最大状态。

第二个方法是在内存池溢出时使用第二个内存池,由于第二个内存池可以继续申请较小块的内存,所以程序可继续运行。代码如下:

18b4619886cc50d89481a2c35f1169fb.gif#include"stdafx.h"18b4619886cc50d89481a2c35f1169fb.gif#include18b4619886cc50d89481a2c35f1169fb.gif#include18b4619886cc50d89481a2c35f1169fb.gif#include18b4619886cc50d89481a2c35f1169fb.gif#include18b4619886cc50d89481a2c35f1169fb.gif#include18b4619886cc50d89481a2c35f1169fb.gifusingnamespacestd;

18b4619886cc50d89481a2c35f1169fb.gifusingnamespaceboost;

18b4619886cc50d89481a2c35f1169fb.gif

18b4619886cc50d89481a2c35f1169fb.gifint_tmain(intargc, _TCHAR*argv[])

724f579eb847bf91dff20d82e6a32e8d.gif

d01baf9b287f1a06d082be5253e99a31.gif...{

788fd394a7cc1f5c037b1b94251c9f3e.gif    boost::pool<>pl(1024*1024);

788fd394a7cc1f5c037b1b94251c9f3e.gif    clock_t clock_begin=clock();

788fd394a7cc1f5c037b1b94251c9f3e.gifintiLength=0;

788fd394a7cc1f5c037b1b94251c9f3e.giffor(inti=0; ;++i)

89f7845f3a81fcad79662ab95b5c9b78.gif

b7680ae2c4e52ef448f5e5d309cb2c79.gif...{

788fd394a7cc1f5c037b1b94251c9f3e.gifvoid*p=pl.malloc();

788fd394a7cc1f5c037b1b94251c9f3e.gifif(p==NULL)

89f7845f3a81fcad79662ab95b5c9b78.gif

b7680ae2c4e52ef448f5e5d309cb2c79.gif...{

788fd394a7cc1f5c037b1b94251c9f3e.gifbreak;

1eb7de1d4600772660d7948d0ed9ef7c.gif        }788fd394a7cc1f5c037b1b94251c9f3e.gif++iLength;

1eb7de1d4600772660d7948d0ed9ef7c.gif    }788fd394a7cc1f5c037b1b94251c9f3e.gif    clock_t clock_end=clock();

788fd394a7cc1f5c037b1b94251c9f3e.gif    cout<

788fd394a7cc1f5c037b1b94251c9f3e.gif

788fd394a7cc1f5c037b1b94251c9f3e.gif    clock_begin=clock();

788fd394a7cc1f5c037b1b94251c9f3e.gif    iLength=0;

788fd394a7cc1f5c037b1b94251c9f3e.gif    boost::pool<>pl2(1024*1024);

788fd394a7cc1f5c037b1b94251c9f3e.giffor(inti=0; ;++i)

89f7845f3a81fcad79662ab95b5c9b78.gif

b7680ae2c4e52ef448f5e5d309cb2c79.gif...{

788fd394a7cc1f5c037b1b94251c9f3e.gifvoid*p=pl2.malloc();

788fd394a7cc1f5c037b1b94251c9f3e.gifif(p==NULL)

89f7845f3a81fcad79662ab95b5c9b78.gif

b7680ae2c4e52ef448f5e5d309cb2c79.gif...{

788fd394a7cc1f5c037b1b94251c9f3e.gifbreak;

1eb7de1d4600772660d7948d0ed9ef7c.gif        }788fd394a7cc1f5c037b1b94251c9f3e.gif++iLength;

1eb7de1d4600772660d7948d0ed9ef7c.gif    }788fd394a7cc1f5c037b1b94251c9f3e.gif    clock_end=clock();

788fd394a7cc1f5c037b1b94251c9f3e.gif    cout<

788fd394a7cc1f5c037b1b94251c9f3e.gif

788fd394a7cc1f5c037b1b94251c9f3e.gifreturn0;

288f2f2748ca34b6348bbced16902be5.gif}

运行结果如下:

2a4b4210b258a8206d996a6dcdc25952.png

结果表明在第一个内存池溢出后,第二个内存池又提供了480M的内存。

5.4 内存池溢出的终极方案

如果无论如何都不能再申请到新的内存了,那么还是老老实实告诉用户重启程序吧。0b1331709591d260c1c78e86d0c51c18.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值