Concurrent Memory Pool:高并发内存池(三层结构)
首先了解一下池化技术和内存池
池化技术
池是在计算机技术中经常使用的一种设计模式主要是将程序中需要经常使用的核心资源先申请出来,放到一个池内,由程序自己管理,这样可以提高资源的使用效率,也可以保证本程序占有的资源数量。经常使用的池技术包括内存池、线程池和连接池等,其中尤以内存池和线程池使用最多。
内存池
内存池(Memory Pool) 是一种动态内存分配与管理技术。
当用new或malloc申请内存空间,用delete或free释放内存空间并且程序长时间运行时,由于所申请内存块的大小不定,频繁使用时会造成大量的内存碎片从而降低程序和操作系统的性能。
内存池是在真正使用内存之前,先申请分配一大块内存留作备用,当我们要申请内存时,从池中取出一块动态分配,当程序员释放内存时,将释放的内存再放入池内,再次申请池可以再取出来使用,并尽量与周边的空闲内存块合并。若内存池不够时,则自动扩大内存池,从操作系统中申请更大的内存池。
内存碎片问题
如下图所示,假设蓝色框表示正在使用的内存空间,那么中间被隔开的地方就无法申请到更大的内存空间,这就导致了内存碎片问题,这种内存碎片叫做内存外碎片。
还有一种内存内碎片的问题,是指当我们在设计内存池时,把内存组织起来分配给你,分配的都是固定的大小,那么假如你申请10字节的内存空间,内存池给了你16字节的空间,那么还有6字节的内存空间就没有使用,这种现象叫做内存内碎片问题。
并发内存池concurrent memory pool
设计这个并发内存池concurrent memory pool主要就是要解决一下几个问题。
- 内存碎片问题。(尽量缓解)
- 性能问题。(提高申请内存的效率)
- 多核多线程环境下,锁竞争问题。
并发内存池concurrent memory pool主要由3部分组成: thread cache(线程缓存)、central cache(中心缓存)、page cache(页缓存)
整体结构如下:
thread cache:线程缓存是每个线程独有的,线程从这里申请内存不需要加锁
central cache:中心缓存是所有线程所共享,达到内存分配在多个线程中更均衡的按需调度的目的
page cache:回收满足条件的span对象,合并相邻的页,组成更大的页,缓解内存碎片的问题
1.第一层thread cache
线程缓存(thread cache) 是每个线程独有的,用于小于64kb的内存的分配,线程从这里申请内存不需要加锁,这里应用到线程本地储存TLS(Thread Local Storage),保证每个线程独享一个thread cache,这样当线程来进行申请内存空间时就不会出现锁竞争问题。
那么大于64kb(16页)的呢?就直接去page cache里申请。
那么大于128页的呢?就直接去系统里申请。
thread cache基本框架:
class ThreadCache//线程缓存
{
private:
FreeList _freeList[NLISTS]; // 自由链表(对象数组)
};
class FreeList//FreeList对象
{
private:
vo