CXYVIP官网源码交易平台_网站源码_商城源码_小程序源码平台-丞旭猿论坛
CXYVIP官网源码交易平台_网站源码_商城源码_小程序源码平台-丞旭猿论坛
CXYVIP官网源码交易平台_网站源码_商城源码_小程序源码平台-丞旭猿论坛

c语言内存池(干货分享)c语言内存池 开源,c++高级话题之 内存池概念、代码实现和详细分析,

1.C语言内存池

如下内容讲解在vs2017 x86上实现;一: 内存池的概念和实现原理概述前面我们曾经说过malloc分配原理,体会到了malloc()这种分配方式来分配内存有一个比较大的内存浪费,尤其是频繁的分配小块内存时,浪费更加明显。

2.c语言内存池实现

所以有一个词叫“内存池”就产生出来,内存池的代码实现千差万别,代码有一定的复杂度,但是一些核心思想确实比较统一的,大家想想,内存池要解决的主要问题是什么呢?(1)减少malloc次数,减少malloc的调用次数就意味着减少对内存的浪费;

3.c++内存池实现

(2)减少了对malloc的调用次数,能不能提高程序的一些运行效率或者说是运行速度呢?从某种程度上来说,能,但是估计效率提高不会太多,因为malloc的执行速度其实是极快的,我们通过测试就能知道,那你改用内存池来处理内存分配,你也需要一定的开销,这个开销估计会比malloc快一点,但应该是快的不明显。

4.C++内存池的设计和实现

内存池的实现原理:(1)用malloc申请一大块内存,你要分配内存的时候,我从这一大块内存中一点点分配给你,当一大块内存差不多用完的时候,我再申请一大块,然后再一点一点的分配给你; 那大家想想,这当然就有效的减少了malloc次数,从而减少了对内存的浪费;当然了,大家也容易想象,因为我是申请一大块,然后一小块一小块分配给你用,那这里边就涉及到怎么分成一小块一小块给你,以及怎么回收的问题,这就是内存池,给我们带来了便利的同时,也带来了代码实现上或者说管理上的难度;

5.c# 内存池

上边我也说了,内存池的代码实现千差万别,不同的人有不同的写法,但不管怎么说,提高运行效率,减少内存浪费这两条是不变的;二:针对一个类的内存池实现演示代码前面,我们学习了类的operator new,operator delete操作符的重载,那么我们能否通过这种重载的手段来实现一个针对一个类的内存池呢?比如前面提到的类A,我们希望用内存池的手段来实现诸如如下这种内存分配的具体实现代码:

6.C++ 实现高性能内存池

A *pa = new A(); delete pa我从网上找了一段相对比较简单,又比较有代表性能够体现内存池用途的代码,和大家一起分享:我先写代码,再解释代码:class A{public: static void *operator new(size_t size); //《c++对象模型探索》

7.c++内存池

static void operator delete(void *phead); static int m_iCount; //用于分配计数统计,每new一次都算 static int m_iMallocCount; //用于统计malloc次数,每malloc一次算一次

8.c语言进程池

private: A *next; static A* m_FreePosi; //总是指向一块可以分配出去的内存的首地址 static int m_sTrunkCount; //一次分配多少倍该类的内存

9.内存池算法

};//——————————————————int A::m_iCount = 0;int A::m_iMallocCount = 0;

10.c语言的内存池的设计与实现

A *A::m_FreePosi = nullptr;int A::m_sTrunkCount = 5; //一次分配5倍的该类内存作为池子的大小//——————————————————

void *A::operator new(size_t size){ //A *ppoint = (A *)malloc(size); //return ppoint; A* tmplink; if (m_FreePosi == nullptr)

{ //为空,我们要申请内存,申请的是很大一块内存 size_t realsize = m_sTrunkCount * size; //申请m_TrunkCount这么多倍的内存 m_FreePosi = reinterpret_cast(new char[realsize]); //这是传统new,调用底层传统malloc

tmplink = m_FreePosi; //把分配出来的这一大块内存链起来,供后续使用 for (; tmplink != &m_FreePosi[m_sTrunkCount – 1]; ++tmplink)

{ tmplink->next = tmplink + 1; } tmplink->next = nullptr; ++m_iMallocCount; } tmplink = m_FreePosi;

m_FreePosi = m_FreePosi->next; ++m_iCount; return tmplink; }void A::operator delete(void *phead){ //free(phead);

(static_cast(phead))->next = m_FreePosi; m_FreePosi = static_cast(phead);}当我们这个operator new函数里干了什么事,我绘制如下图让大家明白该函数的工作过程:刚开始以及if条件成功并且执行for循环内时,得到的示意图应该如下:

跳出if执行if之后的代码后,应该是这样,m_FreePosi总是指向下一个能分配的块的开始地址,最后是把tmplink返回去;

每次new一个对象,m_FreePosi都会往下走,指向下一块待分配的内存首地址,假设我new了5次对象,把这5块都消耗光了,m_Link就会为nullptr了;这个时候,我要new第6次对象的话,那么程序中if (m_Link == nullptr)又成立了,这个时候,程序又会分配出5块内存,大概应该如下:

好,我们大概明白内存怎么分配,我们看看回收:咱们用红色代表已经分配出去的,用绿色代表没有分配出去的;假设当前是这种情况,我想把颜色更红一点的这一块释放掉:

我们看代码,从代码中感受一下如何释放的:

这种释放的感觉,如果大家反映不过来,回去大家要好好想,发挥想象力,实在不明白,自己画图来辅助自己分析,我们要把内存分配,内存释放搞清楚,因为这个程序还是属于比较简单的,以后大家如果面对实战课程的话可能比这个要复杂得多,所以务必要把这种比较简单的琢磨明白;

现在我们这个A类的new时候支持的内存池功能就算写好了,那怎么测试一下呢?咱们在主函数中写如下代码进行测试:clock_t start, end; //包含头文件#include start = clock();

for (int i = 0; i < 5000000; i++){ A *pa = new A();}end = clock(); cout << “申请分配内存的次数为:” << A::m_iCount << ” 实际malloc次数为:” << A::m_iMallocCount << ” 用时(毫秒):” << end-start << endl;

运行结果,多运行几次,我们发现500万次内存分配,大概需要500-800毫秒之间;确实挺快;我们实际的结果是:申请分配内存的次数为:5000000 实际malloc次数为:1000000 用时(毫秒):645

如果我们增加一次分配的块数,从而进一步减少malloc次数看效果:int A::m_sTrunkCount = 500;再次运行:申请分配内存的次数为:5000000 实际malloc次数为:10000 用时(毫秒):434

用时300-500之间,感觉能提升一定速度,但提升有限,原来是100万次malloc,现在是1万次malloc,那就是差了99万次,也就才提升200多毫秒,所以大家看到malloc和自己管理内存速度差不多,真慢不多少

;但你这个A::m_sTrunkCount也不好太大,否则第一次创建出来的块太多,也浪费时间,所以这个效率上提升不多,但内存分配,减少浪费上,肯定是节省了不少;那这个A::m_sTrunkCount到底多大合适,还真不好说,大概测测好像几十个就差不多,大家可以下去自己测试测试。

如果我们用原装不用内存池,我们看看效率如何:在前边增加代码:#define MYMEMPOOL 1void *A::operator new(size_t size){ #ifdef MYMEMPOOL

A *ppoint = (A *)malloc(size); return ppoint;#endifvoid A::operator delete(void *phead){ #ifdef MYMEMPOOL。

free(phead); return;#endif运行结果,感觉整个还是要慢上一些,大概慢上0.5-0.8秒左右;500万次分配内存才慢这么点时间,所以结论还是malloc不慢多少;申请分配内存的次数为:0 实际malloc次数为:0 用时(毫秒):1281。

————三:内存池代码后续说明现在把如下调整为5,int A::m_sTrunkCount = 5;把//#define MYMEMPOOL 1关闭我们循环分配15次内存for (int i = 0; i < 15; i++)

我们在main中打印下并观察一下内存地址for (int i = 0; i < 15; i++){ A *pa = new A(); printf(“%p\n”, pa);}结果:每5个地址都挨着,说明我们的内存池机制发挥了作用;

如果你要关闭内存池,你会发现每次mallo的地址是不一定挨着的;#define MYMEMPOOL 1

那么咱们就给大家演示了内存池的一个具体实现;当然了,这个内存池代码不完善,比如咱们分配内存的时候是new分配的,释放的时候咱们并没有真正的delete释放,而是把这块内存通过链起来,并指示其为一个空闲内存而已;因为大家容易想象,这种内存池技术的实现,你要是真delete来释放内存,还真不好释放,这种代码不好写,那索性咱们就把回收回来的内存攥在手里,需要的时候再分配出去,不需要的时候,一直攥在手里(这个不属于内存泄漏),只要你内存分配不是一直new分配下去,那这个内存池即便后续变得很大,但只要内存有分配,有回收,那这个内存池耗费的内存空间总归还是有限的,只要不超过内存限制,导致程序运行出现资源问题,我们可以接受这种内存池设计的。

当然你程序如果达到内存限制的话,那不管你用不用内存池,都会出问题,那你肯定是光分配内存一直不释放内存了;当然,当整个程序运行即将结束退出的时候,我还是建议大家把分配出去的内存释放掉,这是一个比较好的习惯。

那这个内存池所占用的内存如何写代码来真正的释放掉,这个问题留给大家,我就不带着大家写了,相信只要细心一点,实现出来这段代码应该还是可以的;这里的内存池代码还是以教学和演示为主,当然如果大家要用这段代码,把它适当完善一下当然也不是不行,大家自己把握;

大家听懂了吗?若有问题欢迎入q群:716480601 探讨交流;

© 版权声明
THE END
喜欢就支持一下吧
点赞0赞赏 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容