新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > 一种嵌入式系统的内存分配方案

一种嵌入式系统的内存分配方案

作者:时间:2016-09-12来源:网络收藏

MemLib库中提供了增强的内存分区管理工具,并且增加了一些接口,而且可以设置调试选项。可以检测2类错误:

①尝试分配太大的内存;

②释放内存时发现坏块。

有4种错误处理选项,当发生错误时记录消息或挂起任务。 但是,使用动态malloc/free时要注意到以下几方面的限制。

①因为系统内存分区是一种临界资源,由信号量保护,使用malloc会导致当前调用挂起,因此它不能用于中断服务程序;

②因为进行需要执行查找算法,其执行时间与系统当前的内存使用情况相关,是不确定的,因此对于有规定时限的操作它是不适宜的;

③由于采用简单的最先匹配算法,容易导致系统中存在大量的内存碎片,降低内存使用效率和系统性能。 针对这种情况,一般在系统设计时采用静态分配与动态分配相结合的方法。也就是对于重要的应用,在系统初始化时分配好所需要的内存。在系统运行过程中不再进行内存的分配/释放,这样就避免了因内存的分配释放带来的总是。而且在系统初始化,因为没有内存碎片,对于大的内存块的需求容易满足。对于其它的应用,在运行时进行动态。尤其是某些应用所要求的大量固定尺寸的小内存块,这时就可以采用一次分配多次使用的内存分配。下面详细介绍这种内存分配及其应用场合。

4 一次分配多次使用的内存分配

系统设计中,经常有一些类似于内存数据库的应用。这些应用的特点是在内存中管理一些树,比如以太网交换机中的MAC地址表、VLAN表等,或者路由器中的路由表。这些树是由许多相同尺寸的节点组成的。这样,就可以每次分配一个大的缓冲池,比如包含多个内存单元的数组,每个内存单元用于1个节点。我们用一个空闲链表来管理该数组中的空闲内存单元。每次程序需要分配内存以创建1个新的节点时,就从空闲链表中取1个单元给调用者。程序删除节点并释放内存时,将释放的内存单元返还给空闲链表。如果链表中的空闲内存单元取空了,就再次调用malloc从系统内存中分配一个大的内存块作为新的缓冲池。

采用这样一种方案主要有如下优点:

①减少了malloc/free的调用次数,从而降低了风险,减少了碎片;

②因为从缓冲池中取一个内存单元是时间确定的(当然,如果缓冲池耗尽从而需要重新调用malloc分配除外),因此它可以用于严格时限的场合从而保证实时性;

③它给用户以自由来添加一些用于内存分配和释放的调试函数以及一些统计功能,更好地监测系统中内存的使用情况。

这种方案必然涉及到一个缓冲池的结构。

一般缓冲池的结构由以下几部分组成:单元尺寸、块尺寸(或者单元数目)、缓冲池指针、空闲链表、用于统计和调试的参数等。对缓冲池的操作包括创建缓冲池、释放缓冲池、从缓冲池中分配1个内存单元、释放内存单元回缓冲池等。下面举2个例子说明一下该方案的具体使用情况。

4.1 Intel交换机驱动程序中内存分配

4.1 Intel交换机驱动程序中内存分配

在以Intel的交换芯片为基础的交换机方案中,因为采用的是软件地址学习的方式,需要在内存中维护许多数据,如MAC地址表的软拷贝、VLAN表、静态单播地址表、组播地址表等。这些表都是由一些树组成,每个树由一些固定尺寸的节点组成。一般每个节点几十个字节,每棵树的节点数是可增长的,少则几十,最多可到16K个节点。

因此,很适合于采用该方案,具体的实现如下:

(1)缓冲池结构 BlockMemMgr typedef struct{ MemSize data_cell_size; /*数据单元的尺寸*/ MemSize block_size; /*块尺寸*/ /*下面的变量为预定义的每个管理器最多包含的块数,如64 MAX_BLOCKS_OF_MEM_SIZE*/ Unsigned short blocks_being_used;/*已使用的块数*/ Void mem_ptr[PAX_BLOCKS_OF_MEM_SIZE]; /*块数组*/ SLList free_data_cells_list; /*空闲链表*/ }BlockMemMgr; 结构中的参数包括:单元尺寸、块尺寸、已用块数、所有块的地址、空闲链表(单向链表)。

(2)缓冲池的管理函数

◆block_mem_create:创建块内存管理器,参数包括内存指针(如为NULL,表示自己分配)、块尺寸、单元尺寸、返回管理器指针。 过程如下:

①检验参数合法性。

②单元尺寸4字节对齐,计算每个块中的单元数。对内存指针进行4字节对齐或者分配内存指针。

③初始化结构BlockMemMgr,包括单元尺寸和块尺寸。设置第1个内存块的指针。如果内存是外来的,设置块已用标志(已用为0),表示不能增加块;否则,已用块数设为1。

④创建空闲链表,将块内所有单元添加到链表中,最后一个单元处于链表的最前面。

⑤返回BlockMemMgr。

◆block_mem_destroy:解构一个块内存管理器,释放它所分配的所有内存,调用者负责外部内存的释放。参数为BlockMemMgr。返回成功失败标志。

①参数合法性检测。

②删除单向链表(设链表指针为NULL)。

③如果块是动态分配的,释放它们。 ④释放结构BlockMemMgr。

◆block_malloc:从块内存管理器中分配1个单元

◆block_malloc:从块内存管理器中分配1个单元。参数为BlockMemMgr,返回数据单元指针。

①参数合法性检测。

②判断空闲链表是否为空(是否为NULL)。如果为空,判断是否可以动态分配块,如果不能,返回失败;如果可以动态分配块,则分配1个块,执行与 block_mem_create一样的操作。

③从空闲链表中分配第1个单元,返回其指针。 注意这里有一个小技巧,即数据单元在空闲时其中存放空闲链表的节点信息,而分配后则存放数据内容。

◆block_free:释放1个数据单元,返回块内存管理器。小心不要对1个单元释放2次。参数为BlockMemMgr和单元指针。 ①参数合法性检测。 ②地址比较,判断数据单元属于哪个块。 ③判断数据单元的内容是否为空闲链表节点信息(也就是块内某单元的地址),从而确定是否为2次释放。 ④将该数据单元插入到空闲链表的前面。 ⑤引用该单元的指针设为NULL。 内存管理代码遵守如下约定:①管理的内存是实际可写的内存;②分配内存是4字节或32位对齐;③block_malloc、block_free在中断级调用是部分安全的,除非BLOCK中已经没有空闲CELL,需要重新调用malloc分配新的BLOCK(而malloc和free就不是安全的,因为其中使用了信号量和搜索算法,容易引起中断服务程序阻塞)。当然,block_mem_create和block_mem_destroy必须在进程级调用。



评论


相关推荐

技术专区

关闭