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