STL中的内存管理为两级配置器,一级配置器是当申请内存大于128B时候使用系统函数malloc/free进行申请释放。
二级配置器,将内存块分为大小间距为8的16个8B到128B的等长度的chunk,使用数组+链表管理。数组中存储的是大小相同的用链表链接起来的内存块。在STL中使用长度为16的数组,0处存储8Byte,然后依次16,24,36.....依次加8字节。二级配置器维护着一个内存池,如果所申请的内存块对应的数组的链表下为空,就向池中申请,如果池中为空或者不够则就通过malloc来进行申请内存。
申请内存,首先判断是否超过128B,否则使用一级配置器。使用二级配置器,求得精确申请的内存的大小,内存对齐8。然后再定位到该大小所在的数组下的链表。判断链表是否为空,不空就返回第一个结点给用户,空则查看池中是否为空。内存池中有几种情况,第一有超过20个块的大小,则返回这20个,第二不超过20个,返回最大达到的块数,第三不足一个就将这一个链接到数组中合适的位置。如果为空则就通过malloc向池中注入2倍的所需要的+n内存即这次所申请的内存块大小的40倍大小+n,将20个大小的块连入到该数组下标下,其中的第0块返回给用户,其余的+n留给内存池做下一次的使用。其中的n为附加量。
在内存配置中要对内存申请失败的情况进行处理。使用handle来进行处理,由用户来进行注册,如果发生内存不够所采取的函数,通过函数指针进行设置来处理这种问题。默认情况就直接退出该进程。程序设计者应该对这种问题进行预防,也可以事先进行内存申请,当自己的程序内存申请失败时候然后释放这些内存来确保自己的程序得以存活。
内存管理的手法大同小异,其效率差别重在细节,如memcached,ptmalloc等等,ptmalloc也是分为等级,申请大于128KB的大内存直接通过mmap来进行内存映射,小内存通过化等大小等间距的chunk来进行申请。ptmalloc中将内存块使用bins来进行管理,其中有fast_bin,unstored_bin,bins,top_bins等等。其中,bins是通过长度为128的数组进行管理,前两个用来作为unstored_bin,剩下的前64个用来管理small_bin,其中每个数组下标下连接一个链表,链表中存储的是大小相等的内存块,相邻数组的内存块的大小相差8B。数组的后64个用来管理large_bin,其中每个用来管理的一定范围的大小的内存块,相邻的大小相差64B。fast_bin用来存储释放的小于64B的内存块的大小,主要是为了申请小内存快速,如果每次释放之后进行合并,那么申请小内存块的时候就需要从大内存块中进行切换,效率不高。unstored_bin是用来存放大于64B的内存回收的块以及fast_bin中合并的内存块。top_bin是heap的地址最高处,用来处理在mmap门限值下面的内存块大小的申请。
memcached主要用于缓存,如同STL的二级配置器,将内存分为一个一个小块来进行管理。其中有growth因子来进行调整个内存块大小的间隔。
malloc是调用一次所代价较高,太过频繁会使系统负载太高。通过一次申请一大块内存,然后将所释放的内存回归到自己的内存池中,则其频度大的情况下减轻系统的负载。