在C語言中動態(tài)內(nèi)存的實現(xiàn)主要有兩種方法:
1、通常采用malloc和free函數(shù)實現(xiàn)內(nèi)存的分配和釋放,這也是常用的方法,但是這種方式會導致內(nèi)存碎片的產(chǎn)生,特別是頻繁的分配會導致大量的內(nèi)存碎片產(chǎn)生。
2、內(nèi)存池的使用,內(nèi)存池的基本實現(xiàn)方法主要是采用鏈表的形式將靜態(tài)的內(nèi)存空間動態(tài)的鏈接起來,這樣就能避免內(nèi)存碎片的產(chǎn)生。因此具體的鏈表組織方式就是我們在實際中應該考慮的。
內(nèi)存池是一系列固定大小的內(nèi)存空間,每一個內(nèi)存池主要包括很多內(nèi)存單元(具體的存儲區(qū)域)和內(nèi)存控制單元(控制對應的內(nèi)存單元),每一個內(nèi)存單元大小相同,但是具體的大小依據(jù)需要設計。而控制單元主要是實現(xiàn)每一個子內(nèi)存空間的控制,因此采用一一對應的方式,每一個具體的子內(nèi)存空間分配一個控制單元。靜態(tài)的內(nèi)存單元本來可以采用數(shù)組的方式進行控制,但是數(shù)組要求相同的數(shù)據(jù)類型,而且不便于確定那些內(nèi)存單元是可以處理,那些是不能進行處理的,而鏈表的組織方式則能夠比較清晰的確定空閑的區(qū)域,減少了判定的具體時間,對于不同的下標得計算的時間是不同的,而采用鏈表的方式則能夠?qū)崿F(xiàn)相同的速度訪問,由于不是通過一一比對的方式實現(xiàn)的,采用從空閑鏈表中彈出空閑子內(nèi)存空間的方式就能保證所有的訪問時間是相同的。
內(nèi)存池基本的結(jié)構(gòu)如圖所示:
根據(jù)上面的圖是內(nèi)存池實現(xiàn)的基本框架圖,可以將內(nèi)存池設計為三個部分,主要是mem_pool_struct結(jié)構(gòu)體,mem_pool_node_struct結(jié)構(gòu)體以及內(nèi)存空間(buffer)。mem_pool_struct主要包含一個內(nèi)存池的基本信息。而mem_pool_node_struct則主要控制對應的內(nèi)存空間buffer。而buffer則是具體的子空間�?臻e鏈表、使用鏈表則主要是為了實現(xiàn)對多個內(nèi)存池的控制�;镜慕Y(jié)構(gòu)體定義如下:
/******************************************************
*
*主要完成基本的內(nèi)存控制
*該文檔主要完成結(jié)構(gòu)體和接口的設計
*
*******************************************************/
#ifndef __MEM_POOL_H_H_
#define __MEM_POOL_H_H_
#define NAME_MAX_LENGTH 31
/*采用宏定義實現(xiàn)內(nèi)存池的buffer和控制器的創(chuàng)建*/
#define MEM_POOL_DECLARE(_node_name,_buffer_name,_type,count)\
static mem_pool_node_t _node_name[count]\
static _type _buffer_name[count]
/*內(nèi)存池節(jié)點控制單元*/
typedef struct {
/*內(nèi)存塊控制器的節(jié)點*/
dll_node_t node;
/*指向的內(nèi)存塊起始地址*/
address_t addr;
/*表示該內(nèi)存塊是否被使用*/
bool is_used;
}mem_pool_node_t;
/*內(nèi)存池結(jié)構(gòu)體*/
typedef struct
{
/*用來鏈接不同的內(nèi)存池*/
dll_node_t node;
/*魔數(shù),用來檢測是否有效*/
magic_number_t magic_number;
/*內(nèi)存池名*/
char name[NAME_MAX_LENGTH + 1];
/*內(nèi)存的開始地址*/
address_t addr_start;
/*內(nèi)存的結(jié)束地址*/
address_t addr_end;
/*子內(nèi)存塊的大小*/
size_t buffer_size;
/*子內(nèi)存的個數(shù)*/
size_t buffer_count;
/*節(jié)點指針,便于操作后面而定義的*/
mem_pool_node_t *mpool_head;
/*用來鏈接空閑的子內(nèi)存區(qū)間,也就是與mem_pool_node_t中的node鏈接*/
dll_t free_buffer;
/*統(tǒng)計信息*/
statistic_t stats_nobuf;
}mem_pool_t,*mem_pool_handle_t;
/*防止被C++編譯器編譯*/
#ifdef __cplusplus
extern "C"
{
#endif
error_t mem_pool_create(const char _name[],mem_pool_handle_t *handle,
void *node/*控制塊的指針*/,void *buffer,size_t buffer_size,
size_t buffer_count);
error_t mem_pool_delete(mem_pool_handle_t handle);
void * mem_pool_buffer_alloc(mem_pool_handle_t handle);
error_t mem_pool_buffer_free(mem_pool_handle_t handle,void *buffer);
#ifdef __cplusplus
}
#endif
#endif
由于其中該頭文件主要實現(xiàn)了幾個重要的結(jié)構(gòu)體,分別是mem_pool_t和mem_pool_node_t,分別是內(nèi)存池結(jié)構(gòu)體和內(nèi)存池子空間控制塊結(jié)構(gòu)體。
/**********************************************************
*
*文檔用來實現(xiàn)內(nèi)存池的基本實現(xiàn)
*
* *******************************************************/
#include"mem_pool_h"
#define MPOOL_MAX_NUMBER 8
#define MPOOL_MAX_BUFFER_COUNT 32
/*創(chuàng)建8個內(nèi)存池*/
static mem_pool_t g_mem_pool_t[MPOOL_MAX_NUMBER];
/*空閑鏈表,鏈接空閑的內(nèi)存池*/
static dll_t g_free_link;
/*使用鏈表,鏈接正在使用的內(nèi)存池*/
static dll_t g_used_link;
/**********************************************************
* 該函數(shù)主要完成將上面創(chuàng)建的八個內(nèi)存池,
* 分配通過mem_pool_t中的node連接到空閑
* 鏈表中。
**********************************************************/
static void mem_pool_init()
{
/*具體的依據(jù)鏈表提供的操作完成*/
}
/**********************************************************
*該函數(shù)主要完成內(nèi)存池的創(chuàng)建,其中的參數(shù)主要包含
* _name是內(nèi)存池名,
* handle是內(nèi)存池結(jié)構(gòu)體指針的指針
* node是子內(nèi)存控制塊數(shù)組的指針
* buffer是自內(nèi)存塊數(shù)組的指針
* 以上兩個參數(shù)主要通過MEM_POOL_DECLARE實現(xiàn)
* buffer_size是指子內(nèi)存空間的大小
* buffer_count是值子空間的個數(shù)
*********************************************************/
error_t mem_pool_create(const char _name[],mem_pool_handle_t *handle,
void *node/*控制塊的指針*/,void *buffer,size_t buffer_size,
size_t buffer_count)
{
/*
* 主要完成mem_pool_t結(jié)構(gòu)體的填充,不需要采用malloc創(chuàng)建,
* 而是通過鏈表彈出空間的方式實現(xiàn),將內(nèi)存池對象連接到使用鏈表
*/
/*
* 同時將各個子內(nèi)存空間的控制塊節(jié)點添加到mem_pool_t中的free_buffer中
*/
}
/**********************************************************
*該函數(shù)主要是完成內(nèi)存池的刪除,實質(zhì)上也就是完成mem_pool_t
*結(jié)構(gòu)體中參數(shù)的修改,但是需要注意的是不能刪除正在使用的內(nèi)存池
* *******************************************************/
error_t mem_pool_delete(mem_pool_handle_t handle)
{
/*
*完成將內(nèi)存池對象從使用鏈表中移除,并將其連接到空閑鏈表
*確保所有的子內(nèi)存空間沒有被使用
* */
}
/*************************************************************
*該函數(shù)主要是依據(jù)內(nèi)存池中的鏈表free_buffer中找出空閑的子內(nèi)存空間
*基本的原理就是依據(jù)free_buffer找到子內(nèi)存空間的空閑塊,然后依據(jù)
*mem_pool_node_t中的addr找到內(nèi)存空間的指針,也就得到內(nèi)存空間
*************************************************************/
void * mem_pool_buffer_alloc(mem_pool_handle_t handle)
{
/*從free_buffer中彈出空閑的子內(nèi)存空間*/
/*通過mem_pool_node_t中的addr找到子內(nèi)存空間,并將狀態(tài)修改為使用*/
}
/*************************************************************
* 該函數(shù)主要通過buffer的地址找到對應的子內(nèi)存控制塊,
* 將mem_pool_node中的is_used設置為0即可
* ***********************************************************/
error_t mem_pool_buffer_free(mem_pool_handle_t handle,void *buffer)
{
/*通過buffer找到子內(nèi)存空間控制器對應的下標,
* 然后將mem_pool_node設置為沒有使用
* 最重要的是將該控制器節(jié)點的node壓入mem_pool_t中的free_buffer中
* */
}
由于關(guān)于鏈表的操作沒有實現(xiàn),本文沒有實現(xiàn)具體的操作,但是各個函數(shù)的實現(xiàn)要點都已經(jīng)給出。
內(nèi)存池沒有反復的分配和釋放,這樣就能較好的避免內(nèi)存碎片的產(chǎn)生。其實只要明白基本的模塊就能比較好的實現(xiàn)內(nèi)存池。即內(nèi)存池結(jié)構(gòu)體(mem_pool_t),結(jié)構(gòu)體中將鏈表節(jié)點作為第一個元素主要是為了快速的強制類型轉(zhuǎn)換得到新的數(shù)據(jù)類型指針。比如mem_pool_t的node可以從空閑鏈表中彈出,然后強制類型轉(zhuǎn)換既可以得到mem_pool_t的指針。內(nèi)存控制單元(mem_pool_t)的實現(xiàn)。
實質(zhì)上所有的操作都是基于鏈表的操作,通過內(nèi)存池結(jié)構(gòu)體中的鏈表將所有的子空間控制單元鏈接起來,實現(xiàn)了一個內(nèi)存池的操作。而外部的鏈表則實現(xiàn)了不同內(nèi)存池的操作。
其中的采用數(shù)組的方式進行分配空間主要是為了使后期的操作簡單,能夠依據(jù)數(shù)組的一些特性快速的實現(xiàn)內(nèi)存池空間的管理。
具體的可參考《專業(yè)嵌入式軟件開發(fā)》。