解決問題:malloc在申請內存的時候,內存碎片問題會導致原本內存大小足夠,卻申請大內存失敗;
比如:原本內存還有10M內存,此時先申請4M內存,再申請16Bytes內存,之后把4M內存釋放掉,按理來說,此時應該還有 10M - 16Bytes 內存,但此時,再去申請8M的大內存,則申請失敗。
因為malloc申請的內存,必須是一塊連續的內存,但此時中間已經有16Bytes內存碎片導致內存不連續,所以申請內存失敗;
以下是我針對碎片問題,對內存管理機制做出一種優化方案:在開機初始化內存之后,先申請一塊1M左右內存(根據情況修改大小),用作內存碎片管理,然后把這1M內存分為很多個小內存,并把小內存的地址放在鏈接節點中,之后申請內存時,優先判斷內存碎片管理中是否有滿足大小的小內存。
有的話,直接使用提前申請的小內存就可以了,如果內存管理機制中沒有適合的內存,但重新用malloc()函數申請;
接下來,解釋我寫的碎片管理機制:
1 mm_management_init()初始化
?
void?mm_management_init(unsigned?int?free_memory_start,?unsigned?int?free_memory_end)
?
傳入參數free_memory_start是內存初始化之后,剩余可申請的首地址,該地址,一般會傳入到main函數,如果main()函數沒有傳入該參數的話,可以在內存初始化之后,自己malloc(4)申請一下,把返回的地址作為mm_management_init()函數的第一個參數;
傳入參數free_memory_end是可以申請的最大地址,每個IC各有不同;
mm_management_init()對16bytes,64bytes,256bytes,512bytes,1024bytes,4096bytes這些小內存做優化,提前計算小內存占用的總大小。
然后直接申請這塊大內存占住,再把這塊大內存分配給各個小內存,并記錄在鏈表中,比如:mm_fix_16_head
2 mm_management_malloc()申請函
?
unsigned int mm_management_malloc(unsigned int size)???
?申請內存的時候,先判斷size大小,如果大小可以在內存管理機制中找到,則直接返回提前申請地址,如果大小不滿足,或者小內存已被申請完,則用malloc重新申請。 ???
?在內存管理機制中拿到的小內存,該鏈表節點的標記會設為MM_STATUS_BUSY。
?
3 mm_management_free()
?
void mm_management_free(void *mm_ptr)??
??與mm_management_malloc()相反,先檢查所有小內存鏈表是都有該地址,有的話就把該地址內存清0,并把標記設為MM_STATUS_FREE;如果是用malloc申請的,當時是free()釋放掉;
?
?
???接下來是代碼:
?
#include??這份代碼我寫得還是比較簡單,注釋些也寫得清楚,明白它的原理,應該很容易就看懂。#include #define C_MM_16BYTE_NUM (32) #define C_MM_64BYTE_NUM (16) #define C_MM_256BYTE_NUM (12) #define C_MM_512BYTE_NUM (12) #define C_MM_1024BYTE_NUM (18) #define C_MM_4096BYTE_NUM (30) #define C_MM_16BYTE (16) #define C_MM_64BYTE (64) #define C_MM_256BYTE (256) #define C_MM_512BYTE (512) #define C_MM_1024BYTE (1024) #define C_MM_4096BYTE (4096) #define C_MM_MAX_SIZE C_MM_4096BYTE //碎片管理最大的碎片大小 #define MM_STATUS_FREE (0) //0:表示內存空閑 #define MM_STATUS_BUSY (1) //1:表示內存已被申請 #define MM_STATUS_OK (0) #define MM_STATUS_FAIL (1) typedef struct mm_node_struct { unsigned int *mm_node; //存放內存節點指針 unsigned short iflag; //指針是否空閑 struct P_MM_Node_STRUCT *next; //指向下一個內存節點指針 } MM_Node_STRUCT, *P_MM_Node_STRUCT; typedef struct mm_sdram_struct { unsigned int count; P_MM_Node_STRUCT *next; } MM_SDRAM_STRUCT, *P_MM_SDRAM_STRUCT; static MM_SDRAM_STRUCT mm_fix_16_head; static MM_SDRAM_STRUCT mm_fix_64_head; static MM_SDRAM_STRUCT mm_fix_256_head; static MM_SDRAM_STRUCT mm_fix_512_head; static MM_SDRAM_STRUCT mm_fix_1024_head; static MM_SDRAM_STRUCT mm_fix_4096_head; static P_MM_SDRAM_STRUCT pmm_fix_16_head = &mm_fix_16_head; static P_MM_SDRAM_STRUCT pmm_fix_64_head = &mm_fix_64_head; static P_MM_SDRAM_STRUCT pmm_fix_256_head = &mm_fix_256_head; static P_MM_SDRAM_STRUCT pmm_fix_512_head = &mm_fix_512_head; static P_MM_SDRAM_STRUCT pmm_fix_1024_head = &mm_fix_1024_head; static P_MM_SDRAM_STRUCT pmm_fix_4096_head = &mm_fix_4096_head; static P_MM_Node_STRUCT mm_management_getnode(P_MM_SDRAM_STRUCT pmm_fix_head); static unsigned int mm_management_node_free(P_MM_SDRAM_STRUCT pmm_fix_head, unsigned int *mm_ptr, unsigned int size); static unsigned int *mm_management_ptr = NULL; static unsigned int mm_management_size = 0; /* ** free_memory_start : 開機內存初始化之后,剩余可以申請的地址的首地址 ** free_memory_end : 內存可以申請的最大地址 */ void mm_management_init(unsigned int free_memory_start, unsigned int free_memory_end) { unsigned int mm_usesize=0,offset=0,mm_offset; unsigned char *ptr_tmp; unsigned int i; P_MM_Node_STRUCT pmm_fix_head, pmm_fix_tmp; free_memory_start = (free_memory_start + 3) & (~0x3); // Align to 4-bytes boundary free_memory_end = (free_memory_end + 3) & (~0x3); // Align to 4-bytes boundary do{ //[1]判斷剩余內存是否滿足碎片管理所需大小 mm_usesize = 0; mm_usesize += C_MM_16BYTE * C_MM_16BYTE_NUM; mm_usesize += C_MM_64BYTE * C_MM_64BYTE_NUM; mm_usesize += C_MM_256BYTE * C_MM_256BYTE_NUM; mm_usesize += C_MM_512BYTE * C_MM_512BYTE_NUM; mm_usesize += C_MM_1024BYTE * C_MM_1024BYTE_NUM; mm_usesize += C_MM_4096BYTE * C_MM_4096BYTE_NUM; if(mm_usesize+free_memory_start > free_memory_end) { printf("free memory not enough for mm management,init fail "); break; } mm_management_ptr = (unsigned char *)malloc(mm_usesize); //申請整塊碎片管理內存大小 //如果有malloc_align函數,建議改用malloc_align申請64bit對其的內存 if(mm_management_ptr == NULL) { printf("mm management malloc fail,init fail "); break; } mm_management_size = mm_usesize; ptr_tmp = mm_management_ptr; memset(ptr_tmp, 0x00, mm_usesize); //[2]內存鏈表頭初始化,用于存放以下步驟的子鏈表節點 memset((void*)pmm_fix_16_head, 0x00, sizeof(mm_fix_16_head)); memset((void*)pmm_fix_64_head, 0x00, sizeof(mm_fix_64_head)); memset((void*)pmm_fix_256_head, 0x00, sizeof(mm_fix_256_head)); memset((void*)pmm_fix_512_head, 0x00, sizeof(mm_fix_512_head)); memset((void*)pmm_fix_1024_head, 0x00, sizeof(mm_fix_1024_head)); memset((void*)pmm_fix_4096_head, 0x00, sizeof(mm_fix_4096_head)); //[3]申請16Bytes碎片內存存放在鏈表 mm_offset = 0; mm_fix_16_head.count = C_MM_16BYTE_NUM; pmm_fix_head = pmm_fix_16_head; for(i=0; i iflag = MM_STATUS_FREE; pmm_fix_tmp->next = NULL; offset = (C_MM_16BYTE * i) + mm_offset; //計算小內存碎片在大buf里的偏移地址 pmm_fix_tmp->mm_node = ptr_tmp + offset; pmm_fix_head->next = pmm_fix_tmp; pmm_fix_head = pmm_fix_tmp; } //[4]申請64Bytes碎片內存存放在鏈表 mm_offset += C_MM_16BYTE * C_MM_16BYTE_NUM; mm_fix_64_head.count = C_MM_64BYTE_NUM; pmm_fix_head = pmm_fix_64_head; for(i=0; i iflag = MM_STATUS_FREE; pmm_fix_tmp->next = NULL; offset = (C_MM_64BYTE * i) + mm_offset; //計算小內存碎片在大buf里的偏移地址 pmm_fix_tmp->mm_node = ptr_tmp + offset; pmm_fix_head->next = pmm_fix_tmp; pmm_fix_head = pmm_fix_tmp; } //[5]申請256Bytes碎片內存存放在鏈表 mm_offset += C_MM_64BYTE * C_MM_64BYTE_NUM; mm_fix_256_head.count = C_MM_256BYTE_NUM; pmm_fix_head = pmm_fix_256_head; for(i=0; i iflag = MM_STATUS_FREE; pmm_fix_tmp->next = NULL; offset = (C_MM_256BYTE * i) + mm_offset; //計算小內存碎片在大buf里的偏移地址 pmm_fix_tmp->mm_node = ptr_tmp + offset; pmm_fix_head->next = pmm_fix_tmp; pmm_fix_head = pmm_fix_tmp; } //[6]申請512Bytes碎片內存存放在鏈表 mm_offset += C_MM_256BYTE * C_MM_256BYTE_NUM; mm_fix_512_head.count = C_MM_512BYTE_NUM; pmm_fix_head = pmm_fix_512_head; for(i=0; i iflag = MM_STATUS_FREE; pmm_fix_tmp->next = NULL; offset = (C_MM_512BYTE * i) + mm_offset; //計算小內存碎片在大buf里的偏移地址 pmm_fix_tmp->mm_node = ptr_tmp + offset; pmm_fix_head->next = pmm_fix_tmp; pmm_fix_head = pmm_fix_tmp; } //[7]申請1024Bytes碎片內存存放在鏈表 mm_offset += C_MM_512BYTE * C_MM_512BYTE_NUM; mm_fix_1024_head.count = C_MM_1024BYTE_NUM; pmm_fix_head = pmm_fix_1024_head; for(i=0; i iflag = MM_STATUS_FREE; pmm_fix_tmp->next = NULL; offset = (C_MM_1024BYTE * i) + mm_offset; //計算小內存碎片在大buf里的偏移地址 pmm_fix_tmp->mm_node = ptr_tmp + offset; pmm_fix_head->next = pmm_fix_tmp; pmm_fix_head = pmm_fix_tmp; } //[8]申請4096Bytes碎片內存存放在鏈表 mm_offset += C_MM_1024BYTE * C_MM_1024BYTE_NUM; mm_fix_4096_head.count = C_MM_4096BYTE_NUM; pmm_fix_head = pmm_fix_4096_head; for(i=0; i iflag = MM_STATUS_FREE; pmm_fix_tmp->next = NULL; offset = (C_MM_4096BYTE * i) + mm_offset; //計算小內存碎片在大buf里的偏移地址 pmm_fix_tmp->mm_node = ptr_tmp + offset; pmm_fix_head->next = pmm_fix_tmp; pmm_fix_head = pmm_fix_tmp; } }while(0); printf("mm management init end!!! "); } unsigned int mm_management_malloc(unsigned int size) { int status = MM_STATUS_FAIL; //MM_STATUS_FAIL表示還沒申請到碎片內存 P_MM_Node_STRUCT pmm_fix_node; unsigned int *mm_ptr = NULL; //獲取空閑碎片節點 do{ //[1]判斷申請內存大小是否滿足要求 if(size < 0) { status = MM_STATUS_FAIL; printf("mm management malloc size is error "); return NULL; } //[2]判斷大小是否小于16Byets if(size < C_MM_16BYTE && status == MM_STATUS_FAIL) { pmm_fix_node = mm_management_getnode(pmm_fix_16_head); if(pmm_fix_node != NULL) { status = MM_STATUS_OK; break; } } //[3]判斷大小是否小于64Byets if(size < C_MM_64BYTE && status == MM_STATUS_FAIL) { pmm_fix_node = mm_management_getnode(pmm_fix_64_head); if(pmm_fix_node != NULL) { status = MM_STATUS_OK; break; } } //[4]判斷大小是否小于256Byets if(size < C_MM_256BYTE && status == MM_STATUS_FAIL) { pmm_fix_node = mm_management_getnode(pmm_fix_256_head); if(pmm_fix_node != NULL) { status = MM_STATUS_OK; break; } } //[5]判斷大小是否小于512Byets if(size < C_MM_512BYTE && status == MM_STATUS_FAIL) { pmm_fix_node = mm_management_getnode(pmm_fix_512_head); if(pmm_fix_node != NULL) { status = MM_STATUS_OK; break; } } //[6]判斷大小是否小于1024Byets if(size < C_MM_1024BYTE && status == MM_STATUS_FAIL) { pmm_fix_node = mm_management_getnode(pmm_fix_1024_head); if(pmm_fix_node != NULL) { status = MM_STATUS_OK; break; } } //[7]判斷大小是否小于4096Byets if(size < C_MM_4096BYTE && status == MM_STATUS_FAIL) { pmm_fix_node = mm_management_getnode(pmm_fix_4096_head); if(pmm_fix_node != NULL) { status = MM_STATUS_OK; break; } } }while(0); if(status == MM_STATUS_OK) { mm_ptr = pmm_fix_node->mm_node; pmm_fix_node->iflag = MM_STATUS_BUSY; } else { mm_ptr = (unsigned int *)malloc(size); } return (unsigned int *)mm_ptr; } void mm_management_free(void *mm_ptr) { unsigned int i; int status = MM_STATUS_FAIL; P_MM_Node_STRUCT pmm_fix_node; do{ //[1]如果地址是16Bytes碎片地址,則釋放內存 status = mm_management_node_free(pmm_fix_16_head, mm_ptr, C_MM_16BYTE); if(status == MM_STATUS_OK) break; //[2]如果地址是64Bytes碎片地址,則釋放內存 status = mm_management_node_free(pmm_fix_64_head, mm_ptr, C_MM_64BYTE); if(status == MM_STATUS_OK) break; //[1]如果地址是256Bytes碎片地址,則釋放內存 status = mm_management_node_free(pmm_fix_256_head, mm_ptr, C_MM_256BYTE); if(status == MM_STATUS_OK) break; //[1]如果地址是512Bytes碎片地址,則釋放內存 status = mm_management_node_free(pmm_fix_512_head, mm_ptr, C_MM_512BYTE); if(status == MM_STATUS_OK) break; //[1]如果地址是1024Bytes碎片地址,則釋放內存 status = mm_management_node_free(pmm_fix_1024_head, mm_ptr, C_MM_1024BYTE); if(status == MM_STATUS_OK) break; //[1]如果地址是4096Bytes碎片地址,則釋放內存 status = mm_management_node_free(pmm_fix_4096_head, mm_ptr, C_MM_4096BYTE); if(status == MM_STATUS_OK) break; }while(0); if(status == MM_STATUS_OK) { //do nothing,在mm_management_node_free函數中已經將pmm_fix_node->iflag設為MM_STATUS_FREE } else { free(mm_ptr); } } //獲取MM_SDRAM_STRUCT里的空閑節點 static P_MM_Node_STRUCT mm_management_getnode(P_MM_SDRAM_STRUCT pmm_fix_head) { P_MM_SDRAM_STRUCT pmm_fix_head_tmp = pmm_fix_head; P_MM_Node_STRUCT pmm_fix_node = pmm_fix_head_tmp->next; unsigned int count = pmm_fix_head_tmp->count; unsigned int i; for(i=0; i iflag == MM_STATUS_FREE) break; pmm_fix_node = pmm_fix_node->next; } if(i < count) return pmm_fix_node; else return NULL; } //比較MM_SDRAM_STRUCT的所有節點,如果地址一致,則釋放地址 static unsigned int mm_management_node_free(P_MM_SDRAM_STRUCT pmm_fix_head, unsigned int *mm_ptr, unsigned int size) { P_MM_SDRAM_STRUCT pmm_fix_head_tmp = pmm_fix_head; P_MM_Node_STRUCT pmm_fix_node = pmm_fix_head_tmp->next; unsigned int count = pmm_fix_head_tmp->count; unsigned int i; for(i=0; i mm_node == mm_ptr) { if(pmm_fix_node->iflag == MM_STATUS_FREE) { printf("mm management have been free "); } else { pmm_fix_node->iflag = MM_STATUS_FREE; memset((void *)mm_ptr, 0x00, size); //釋放內存后,把碎片內存清0 } return MM_STATUS_OK; } pmm_fix_node = pmm_fix_node->next; } return MM_STATUS_FAIL; }
?
說一下這個機制的優缺點:
優點:
小內存申請的時候,先去提前申請好的內存中獲取,這樣可以很好地解決內存碎片問題。
缺點以及優化:
1.碎片管理機制可申請的碎片數量是有限的,當數量被申請完之后,還是得重新用malloc申請;但是這可以通過我定義的 C_MM_16BYTE_NUM 和 C_MM_16BYTE 這些宏定義修改碎片數量,根據項目需要修改數量,也是能很好的優化此問題;
2.比如我要申請4個Bytes,但此時,16,64,256,512,1024這幾個鏈表已經用完了,那此時它會用4096這個鏈表去給4Bytes使用,當然,這同樣可以修改C_MM_16BYTE_NUM 和 C_MM_16BYTE 這些宏定義優化這個問題。
審核編輯:湯梓紅
?
評論
查看更多