在用C語言開發時,特別是在服務器端,內存的使用會成為系統性能的一個瓶頸,如頻繁的分配和釋放內存,會不斷的增加系統的內存碎片,影響內核之後分配內存的效率,這個時候一個比較可行的做法是采用內存池,先分配好比較多的內存,然後在這個已經分配的內存裡使用內存,這樣就不需要內核過多的參與內存分配和釋放的過程。
內存池根據應用不同有多種實現的策略,如有些分配很大的內存,然後將內存分配成大小相等的塊,並將每個塊鏈接起來進行管理。
下面對模型介紹的時候,為了簡單,不加入用於調試的編寫技巧和為之准備的結構,其實主要是省去間接調用,有時為了調試,會將文件及所在行以及主要的變量狀態輸出。
一,內存池訪問接口
創建大小為size的新的內存池。
- pool_t _pool_new_heap(int size);
從指定內存池中分配大小為size的內存空間, 這些空間會在內存池釋放時,被自動的釋放。
- void *pool_malloc(pool_t, int size);
內存池的大小,返回內存池中所有內存塊的大小總和
- int pool_size(pool_t p);
釋放內存池,這會導致所有內存被釋放,同時內存池本身也被釋放
- void pool_free(pool_t p);
還有其它的一些接口,但這些是主要的接口。
二,數據結構
- struct pheap
- {
- void *block;
- int size, used;
- };
該結構表示內存池中一個內存塊的抽象表示,
- block 用於指向由malloc所分配的內存地址。
- size 表示block所指向地址的內存大小。
- used 表示多少處於已經使用的狀態。在分配內存時,這個域很重要,它表示內存塊可以被分配的偏移值,也就是從used開始的內存都是可以被從內存池中分配出去的。
- struct pfree
- {
- pool_cleanup_t f;
- void *arg;
- struct pheap *heap;
- struct pfree *next;
- };
- typedef void (*pool_cleanup_t)(void *arg);
這個結構用於實現一個鏈表,將所有的內存塊鏈接起來。每一個內存塊,對映一個這個結構,也就是每個struct pheap結構,都有一個struct pfree結構將其封裝起來,這個結構主要實現下面幾個功能:
- 實現內存塊的鏈表,用struct pfree *next連接起來,這是一個單鏈表。
- 內存塊釋放的回調。注冊在釋放內存時,如果釋放這個內存塊,主要是通過pool_cleanup_t f和void *arg兩個域來完成這個功能。
- pheap域用於指向需要被放入鏈表的內存塊,就是前面的結構。
- typedef struct pool_struct
- {
- int size;
- struct pfree *cleanup;
- struct pfree *cleanup_tail;
- struct pheap *heap;
- } _pool, *pool_t;
結構中的域代表如下:
heap:指向內存池中最新申請的內存塊,在每次申請內存塊時,都會將其指向新的內存塊。
cleanup和cleanup_tail:指向鏈表的頭和尾的指針。
size:表示內存池中內存的大小,包括所有的內存塊。
這個結構的主要功能如下:
- 管理內存塊。通過cleanup和clean_tail兩個指針,因為內存塊在內存池中是以單鏈表的形式組織的,這兩個指針分別指向鏈表的頭和尾指針。
- 內存池中可用的內存大小。通過size域來統計完成。
- 獲取最新的內存塊指針。通過heap指針在每次分配內存塊時重新賦值來實現。
這個內存池的實現,主要是依靠上面三個數據結構來完成,其實估計已經知道的差不多了。下面再討論一些基本的