內存池實現:elr-memery-pool
簡介
這是一款高效、靈活、跨平臺的內存池實現。使用MIT Licence發布,完全不排斥商業使用。它已經在許多生產環境中使用了。在該實現中內存被劃分為節點(node)和切片(slice)。node一大塊內存,slice是node上的小片內存,從內存池中申請的每一個內存都屬于一個slice。每一個內存池實例里德slice都是一樣大小的,所以這個內存池更像對象池。但是仍然可以基于該內存池實現一款更加靈活的可以從中申請不同尺寸的內存的內存池。
node鏈接成一個鏈表,可以使用的slice也鏈接成一個鏈表。當從內存池中申請內存時,首先檢查是否有空閑的slice,如果有取出一個;如果沒有,就檢查最近申請的node里是否還有從未使用過的切片。如果最近申請的node里有從未使用過的slice,那么取出一個;如果沒有將這個node添加到 node鏈表的頭部再申請一個新node并從中取出一個slice返回。釋放內存時,僅僅需要將slice插入到空閑的slice鏈表頭部。
這個內存池被組織為樹狀結構。當創建一個內存池時,可以為其指定父內存池,在調用elr_mpl_create時使用父內存池的指針作為第一個參數即可。當一個內存池被銷毀時,它的子內存池也會被銷毀。所以當一個內存池和它的子內存池不再使用時不必將所有的內存池一一銷毀,僅僅為父內存池調用銷毀接口即可。如果在創建內存池時不指定父內存池,那么一個全局的內存池就是它的父內存池。它是在第一次調用初始化內存池函數(elr_mpl_init)時被創建的。所有的內存池結構所占據的內存空間都來自于這個全局內存池。在最后一次調用終止化(elr_mpl_finalize)內存池時這個全局內存池被銷毀。同時可以看出所有的內存池實例都是這個全局內存池的直接或者間接的子內存池。那么當elr_mpl_finalize被調用后所有的內存池實例也將被銷毀。這將內存泄露的可能性降到了最低。
這個內存池也支持多線程。如果需要在多線程環境下使用它,就需要實現elr_mtx.h中定義的六個接口并且在編譯時定義宏 ELR_USE_THREAD。幸運的是實現它們非常簡單,并且已經提供了一個windows平臺下的實現。在提供windows平臺下的實現時也考慮到了linux的兼容性。所以原子計數器類型和計數器類型(counter(interger) type and counter value type )被分別定義了。在windows平臺下并沒有對原子計數器類型單獨定義,而是提供一個被volatile修飾的LONG類型。在LONG和 volatile LONG之間賦值是被允許的。在linux平臺下原子計數器類型被定義為這樣:typedef struct { volatile int counter; } atomic_t; 。在int和atomic_t之間賦值是違法語法的。
這個內存池在生產環境中被證明是非常有效的。即使如此這個內存池也有很大的改良空間。在多線程環境下使用時,每一個內存池實例都擁有一個互斥體,很多情形下這不是必須的。所以這個內存池至少有兩個地方可以改進。第一,減少對互斥體的消耗,這對嵌入式系統來說是非常有意義的。第二,擴展它使得它能夠像 appache的內存池一樣可以從內存池實例中申請多種規則尺寸的內存塊。
使用示例#include <stdio.h>
#include <stdlib.h>
#include "elr_mpl.h"
int main()
{
elr_mpl_t mypool = ELR_MPL_INITIALIZER;
elr_mpl_t mysubpool = ELR_MPL_INITIALIZER;
void* mem = NULL;
int len = 0;
elr_mpl_init();
mypool = elr_mpl_create(NULL,256);
printf("%s\n","create a memory pool: mypool.");
mysubpool = elr_mpl_create(&mypool,128);
printf("%s\n","create a sub memory pool of mypool, name is mysubpool.");
mem = elr_mpl_alloc(&mysubpool);
printf("%s\n","alloc a memory block form mysubpool.");
len = elr_mpl_size(mem);
printf("the memory block size is %d.\n",len);
elr_mpl_free(mem);
printf("give back the memory block to mysubpool.\n",len);
mem = elr_mpl_alloc(&mypool);
printf("%s\n","alloc a memory block form mypool.");
len = elr_mpl_size(mem);
printf("the memory block size is %d.\n",len);
elr_mpl_free(mem);
printf("give back the memory block to mypool.\n",len);
elr_mpl_destroy(&mypool);
printf("destroy mypool.\n",len);
printf("when mypool has destoryed, it`s sub pool, mysubpool, did %s destoryed.\n",
elr_mpl_avail(&mysubpool) == 0?"also":"not");
elr_mpl_finalize();
getchar();
return 0;
}
https://code.google.com/p/elr-memery-pool/