您的位置 首页 新品

内存非常重要!浅谈嵌入式裸机编程最重要的事

内存非常重要!浅谈嵌入式裸机编程最重要的事-在嵌入式裸机编程中,作为一名初级的CODER。经常要与CPU、内存等打交道。CPU作为系统的动力源,其重要程度不言而喻。但是,在裸机编程中,对内存的管理也不容忽视。

在嵌入式裸机编程中,作为一名初级的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);

}

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/xinpin/103257.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部