內存堆的初始化函數,主要是告知內存堆的起止地址,以及初始化空閒列表,mem_malloc( ) 申請分配內存。將總共須要的字節數做爲參數傳遞給該函數,返回值是指向最新分配的內存的指針,而若是內存沒有分配好,則返回值是 NULL。內存的分配和釋放,不能在中斷函數裏面進行。內存堆是全局變量,所以內存的申請、釋放操做作了線程安全保護,若是有多個線程在同時進行內存申請和釋放,那麼可能會由於信號量的等待而致使申請耗時較長。mem_free()釋放空間到內存堆中。c#
mem_init()分配策略:事先定義好大小的內存塊中進行管理,其內存分配的策略是採用最快合適(First Fit)方式,只要找到一個比所請求的內存大的空閒塊,就從中切割出合適的塊,並把剩餘的部分返回到動態內存堆中。分配的內存塊有個最小大小的限制,要求請求的分配大小不能小於 MIN_SIZE,不然請求會被分配到 MIN_SIZE 大小的內存空間。數組
內存釋放的過程是相反的過程,但分配器會查看該節點先後相鄰的內存塊是否空閒,若是空閒則合併成一個大的內存空閒塊。緩存
優勢:就是內存浪費小,比較簡單,適合用於小內存的管理。缺點:就是若是頻繁的動態分配和釋放,可能會形成嚴重的內存碎片,若是在碎片狀況嚴重的話,可能會致使內存分配不成功。安全
void mem_init(void) { struct mem *mem; //檢查對齊 LWIP_ASSERT("Sanity check alignment", (SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0); /* align the heap 堆棧對齊*/ ram = LWIP_MEM_ALIGN(ram_heap); /* initialize the start of the heap */ mem = (struct mem *)ram; mem->next = MEM_SIZE_ALIGNED; //下一塊指向這塊的末尾 //#define MEM_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEM_SIZE) 就是內存大小 順便對齊 mem->prev = 0; mem->used = 0; /* initialize the end of the heap */ ram_end = (struct mem *)&ram[MEM_SIZE_ALIGNED]; //&(ram+1600)即末尾 ram_end->used = 1; //用了一塊內存 ram_end->next = MEM_SIZE_ALIGNED; ram_end->prev = MEM_SIZE_ALIGNED; mem_sem = sys_sem_new(1); //無操做系統define 1 /* initialize the lowest-free pointer to the start of the heap */ lfree = (struct mem *)ram; MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED); //mem_stats 內存狀態 }
// 沒有使用 MEM_USE_POOLS 時mem定義 struct mem { /** index (-> ram[next]) of the next struct */ mem_size_t next; /** index (-> ram[next]) of the next struct */ mem_size_t prev; /** 1: this area is used; 0: this area is unused */ u8_t used; };
MEM_STATS_AVAIL(x,y)
函數
#if MEM_STATS //0 #define MEM_STATS_AVAIL(x, y) lwip_stats.mem.x = y #else #define MEM_STATS_AVAIL(x, y)
memp_init()分配策略:分配類型大小固定的內存區,分配的個數是能夠用戶配置的,用戶應該根據協議棧實際使用情況this
進行配置。把協議棧中全部內存區放在一片連續的內存區域,這就是一個大的緩衝池。簡單說就是先開闢一堆各類類型的內存區放那,要用時直接取就好了。spa
memp_num:組用於保存各類類型緩衝池的成員數目操作系統
memp_sizes:組用於保存各類類型緩衝池的結構大小.net
memp_tab:指針數組用於指向各類類型緩衝池當前空閒節點線程
memp_init():內存池的初始化,主要是爲每種內存池創建鏈表 memp_tab,其鏈表是逆序的,此外,若是有統計功能使能的話,也把記錄了各類內存池的數目。
memp_malloc():若是相應的 memp_tab 鏈表還有空閒的節點,則從中切出一個節點返回,不然返回空。
memp_free():把釋放的節點添加到相應的鏈表 memp_tab 頭上
優勢:實現簡單,內存的分配、釋放效率高,能夠有效防止內存碎片的產生。缺點:是會浪費部份內存。
void memp_init(void) { struct memp *memp; //下面介紹 u16_t i, j; for (i = 0; i < MEMP_MAX; ++i) { MEMP_STATS_AVAIL(used, i, 0); MEMP_STATS_AVAIL(max, i, 0); MEMP_STATS_AVAIL(err, i, 0); MEMP_STATS_AVAIL(avail, i, memp_num[i]); } memp = LWIP_MEM_ALIGN(memp_memory); //memp_memory見http://my.oschina.net/u/274829/blog/271361 /* for every pool: */ for (i = 0; i < MEMP_MAX; ++i) { memp_tab[i] = NULL; /* create a linked list of memp elements */ for (j = 0; j < memp_num[i]; ++j) { memp->next = memp_tab[i]; //memp_tab[]至關於 tmp緩存 memp_tab[i] = memp; memp = (struct memp *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i] #if MEMP_OVERFLOW_CHECK + MEMP_SANITY_REGION_AFTER_ALIGNED #endif ); } } #if MEMP_OVERFLOW_CHECK //溢出檢查 memp_overflow_init(); //沒用 /* check everything a first time to see if it worked */ memp_overflow_check_all(); #endif /* MEMP_OVERFLOW_CHECK */ }
struct memp
struct memp { struct memp *next; //下一個鏈表 #if MEMP_OVERFLOW_CHECK const char *file; int line; #endif /* MEMP_OVERFLOW_CHECK */ };
MEMP_STATS_AVAIL
#if MEMP_STATS //0 #define MEMP_STATS_AVAIL(x, i, y) lwip_stats.memp[i].x = y #else #define MEMP_STATS_AVAIL(x, i, y)