在嵌入式裸机编程中,作为一名初级的CODER。常常要与CPU、内存等打交道。CPU作为体系的动力源,其重要程度显而易见。可是,在裸机编程中,对内存的办理也不容忽视。假如略微不留意,轻则,或许形成内存走漏,重则形成内存拜访反常。导致体系死机。
嵌入式产品,对安稳性要求及其严厉。动不动就死机,那可就费事大了。以下,是我自己对嵌入式体系裸机编程的内存办理的一些简介。
1. 万万不可运用体系自带的malloc和free。
malloc和free在PC编程中是很好用的一种内存分配手法。可是,其在嵌入式中,就未必好用了。因为嵌入式裸机编程中,无MMU,即内存办理单元。无法完成对内存进行动态映射(不明白什么叫动态映射的同学,能够参阅网上的材料)。也便是说,实际上,malloc和free并不能完成动态的内存的办理。这需要在发动阶段专门给其分配一段闲暇的内存区域作为malloc的内存区。如STM32中的发动文件startup_stm32f10x_md.s中见以下信息:
[plain] view plain copy
Heap_Size EQU 0x00000800 AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
其间,Heap_Size即界说一个宏界说。数值为0x00000800。Heap_Mem则为请求一块接连的内存,巨细为 Heap_Size。简化为C言语版别如下:
#define Heap_Size 0x00000800
unsigned char Heap_Mem[Heap_Size] = {0};
在这里请求的这块内存,在接下来的代码中,被注册进体系中给malloc和free函数所运用:
__user_initial_stackheap
LDR R0, = Heap_Mem ; 回来体系中堆内存开始地址
LDR R1, =(Stack_Mem + Stack_Size)
LDR R2, = (Heap_Mem + Heap_Size); 回来体系中堆内存的完毕地址
LDR R3, = Stack_Mem
BX LR
就如上面剖析的那样,其实,在裸机编程的时分,对堆内存的办理。并非是智能化的,并非你想请求多少就多少。而是运用一块固定的内存用作堆内存的分配。这在规划的时分,往往不是最佳的计划。这块内存,假如被屡次依照不同的巨细进行请求,就会形成内存碎片。终究导致无法请求到满足的内存。导致体系运转犯错。这在本来内存就现已很少的嵌入式体系中,更是不能承受的。所以,主张是把那个Heap_Size设置成 0 吧。抛弃其运用吧。
而更为丧命的是,有些malloc,free函数,因为工程人员的偷闲。完成乃至或许如下:
unsigned char mem_buffer[512];
unsigned char *mem_offset = & mem_buffer;
void *malloc(int size)
{
unsigned char *tmp = mem_offset;
mem_offset += size;
return (void *)tmp;
}
void free(void *mem)
{
mem_offset = mem;
}
2. 更好的代替计划:内存池。
或许有些同学,觉得:内存池,这是什么东西?
内存池,简练地来说,便是预先分配一块固定巨细的内存。今后,要请求固定巨细的内存的时分,即可从该内存池中请求。用完了,天然要放回去。留意,内存池,每次请求都只能请求固定巨细的内存。这姿态做,有许多优点:
(1)每次动态内存请求的巨细都是固定的,能够有用避免内存碎片化。(至于为什么,能够想想,每次请求的都是固定的巨细,收回也是固定的巨细)
(2)效率高,不需要杂乱的内存分配算法来完成。请求,开释的时刻杂乱度,能够做到O(1)。
(3)完成简略,易用。
(4)内存的请求,开释都在可控的规模之内。不会呈现今后运转着,运转着,就再也请求不到内存的状况。
内存池,并非什么很厉害的技能。完成起来,其实能够做到很简略。只需要一个链表即可。在初始化的时分,把全局变量请求来的内存,一个个放入该链表中。在请求的时分,只需要取出头部并回来即可。在开释的时分,只需要把该内存刺进链表。以下是一种简略的比如(运用移植来的linux内核链表,对该链表的移植,今后有时刻再去剖析):
#define MEM_BUFFER_LEN 5 //内存块的数量
#define MEM_BUFFER_SIZE 256 //每块内存的巨细
//内存池的描绘,运用联合体,表现贫民的才智。就如,我一同学说的:一个字节,恨不能掰成8个字节来用。
typedef union mem {
struct list_head list;
unsigned char buffer[MEM_BUFFER_SIZE];
}mem_t;
static union mem gmem[MEM_BUFFER_LEN];
LIST_HEAD(mem_pool);
//分配内存
void *mem_pop()
{
union mem *ret = NULL;
psr_t psr;
psr = ENTER_CRITICAL();
if(!list_empty(&mem_pool)) { //有可用的内存池
ret = list_first_entry(&mem_pool, union mem, list);
//printf("mem_pool = 0x%p ret = 0x%p\n", &mem_pool, &ret->list);
list_del(&ret->list);
}
EXIT_CRITICAL(psr);
return ret;//->buffer;
}
//收回内存
void mem_push(void *mem)
{
union mem *tmp = NULL;
psr_t psr;
tmp = (void *)mem;//container_of(mem, struct mem, buffer);
psr = ENTER_CRITICAL();
list_add(&tmp->list, &mem_pool);
//printf("free = 0x%p\n", &tmp->list);
EXIT_CRITICAL(psr);
}
//初始化内存池
void mem_pool_init()
{
int i;
psr_t psr;
psr = ENTER_CRITICAL();
for(i=0; i
list_add(&(gmem[i].list), &mem_pool);
//printf("add mem 0x%p\n", &(gmem[i].list));
}
EXIT_CRITICAL(psr);
}