http://www.wanxiangshu.com

malloc和内存池技术的区别 内存池技术性能优化方案

大家生活中肯定都有这样的经验,那就是大众化的产品都比较便宜,但便宜的大众产品就是一个词,普通;而可以定制的产品一般都价位不凡,这种定制的产品注定不会在大众中普及,因此定制产品就是一个词,独特。

有的同学可能会有疑问,你不是要聊技术吗?怎么又说起消费了?

原来技术也有大众货以及定制品。

通用 VS 定制

作为程序员(C++/C++)我们知道申请内存使用的是malloc,malloc其实就是一个通用的大众货,什么场景下都可以用,但是什么场景下都可以用就意味着什么场景下都不会有很高的性能。

pIYBAGA95wmAJDzKAAGIp7NP6uc902.png

malloc性能不高的原因一在于其没有为特定场景做优化,除此之外还在于malloc看似简单,但是其调用过程是很复杂的,一次malloc的调用过程可能需要经过操作系统的配合才能完成。 那么调用malloc时底层都发生了什么呢?简单来说会有这样典型的几个步骤:

malloc开始搜索空闲内存块,如果能找到一块大小合适的就分配出去

如果malloc找不到一块合适的空闲内存,那么调用brk等系统调用扩大堆区从而获得更多的空闲内存

malloc调用brk后开始转入内核态,此时操作系统中的虚拟内存系统开始工作,扩大进程的堆区,注意额外扩大的这一部分内存仅仅是虚拟内存,操作系统并没有为此分配真正的物理内存

brk执行结束后返回到malloc,从内核态切换到用户态,malloc找到一块合适的空闲内存后返回

pIYBAGA95xqAB7Y0AAJcTxFMIT4140.png

以上就是一次内存申请的完整过程,我们可以看到,一次内存申请过程其实是非常复杂的,关于这个问题的详细讨论你可以参考这里。 既然每次分配内存都要经过这么复杂的过程,那么如果程序大量使用malloc申请内存那么该程序注定无法获得高性能。 幸好,除了大众货的malloc,我们还可以私人定制,也就是针对特定场景自己来维护内存申请和分配,这就是高性能高并发必备的内存池技术。

内存池技术有什么特殊的吗? 有的同学可能会说,等等,那malloc和这里提到的内存池技术有什么区别呢? 第一个区别在于我们所说的malloc其实是标准库的一部分,位于标准库这一层;而内存池是应用程序的一部分。

pIYBAGA95zKAPnnOAACcrVHiG8U029.png

其次在于定位,我们自己实现的malloc其实也是定位通用性的,通用性的内存分配器设计实现往往比较复杂,但是内存池技术就不一样了,内存池技术专用于某个特定场景,以此优化程序性能,但内存池技术的通用性是很差的,在一种场景下有很高性能的内存池基本上没有办法在其它场景也能获得高性能,甚至根本就不能用于其它场景,这就是内存池这种技术的定位。

pIYBAGA9502AMxMZAAI-9p5ADk0404.png

那么内存池技术是怎样优化性能的呢?

内存池技术原理 简单来说,内存池技术一次性获取到大块内存,然后在其之上自己管理内存的申请和释放,这样就绕过了标准库以及操作系统:

o4YBAGA9532AWEUTAAFyO08Rcxc293.png

也就是说,通过内存池,一次内存的申请再也不用去绕一大圈了。 除此之外,我们可以根据特定的使用模式来进一步优化,比如在服务器端,每次用户请求需要创建的对象可能就那几种,那么这时我们就可以在自己的内存池上提前创建出这些对象,当业务逻辑需要时就从内存池中申请已经创建好的对象,使用完毕后还回内存池。 因此我们可以看到,这种为某些应用场景定制的内存池相比通用的比如malloc内存分配器会有大的优势。 接下来我们就着手实现一个。

实现内存池的考虑 值得注意的是,内存池实际上有很多的实现方法,在这里我们还是以服务器端编程为例来说明。 假设你的服务器程序非常简单,处理用户请求时只使用一种对象(数据结构),那么最简单的就是我们提前申请出一堆来,使用的时候拿出一个,使用完后还回去:

pIYBAGA9556AE5n_AAFWKsuIG98361.png

怎么样,足够简单吧!这样的内存池只能分配特定对象(数据结构),当然这样的内存池需要自己维护哪些对象是已经被分配出去的,哪些是还没有被使用的。 但是,在这里我们可以实现一个稍微复杂一些的,那就是可以申请不同大小的内存,而且由于是服务器端编程,那么一次用户请求过程中我们只申请内存,只有当用户请求处理完毕后一次性释放所有内存,从而将内存申请释放的开销降低到最小。 因此,你可以看到,内存池的设计都是针对特定场景的。 现在,有了初步的设计,接下来就是细节了。

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。