由于RTT是实时操作系统,其对时间有着严格的要求,内存分配的时间往往要比通用操作系统要更苛刻。
首先,分配内存的时间必须是确定的。一般内存管理算法是根据需要存储的数据的长度在内存中去寻找一个与这段数据相适应的空闲内存块,然后将数据存储在里面。而寻找这样一个空闲内存块所耗费的时间是不确定的,这对于实时系统来说,是不可接受的,实时系统必须要保证内存块的分配过程在可预测的确定时间内完成,否则实时任务对外部事件的响应也将变得不可确定。
其次,随着内存不断被分配和释放,整个内存区域会产生越来越多的碎片(因为在使用过程中,申请了一些内存,其中一些释放了,导致内存空间中存在一些小的内存块,它们地址不连续,不能够作为一整块的大内存分配出去),系统中还有足够的空闲内存,但因为它们地址并非连续,不能组成一块连续的完整内存块,会使得程序不能申请到大的内存。对于通用系统而言,这种不恰当的内存分配算法可以通过重新启动系统来解决(每个月或者数个月进行一次),但是对于那些需要常年不间断地工作于野外的嵌入式系统来说,就变得让人无法接受了。所以实时操作系统的内存分配算法应该要尽可能妥善的改进碎片问题。
最后,嵌入式系统的资源环境也是不尽相同,有些系统的资源比较紧张,只有数十KB的内存可供分配,而有些系统则存在数MB的内存,如何为这些不同的系统,选择适合它们的高效率的内存分配算法,就将变得复杂化。所以实时操作系统的内存分配算法要尽可能多的适应内存不等的各种平台。
RTT操作系统在内存管理上,针对以上问题,提供了不同的内存分配算法。
大体上可分为两类:静态分区内存管理与动态内存管理,而动态内存管理又根据可用内存的多少划分为两种情况:一种是针对小内存块的分配管理(小内存管理算法),另一种是针对大内存块的分配管理(SLAB管理算法)。
这里先来看看其提供的一种名为内存池(Memory Pool)的内存分配管理算法,内存池是一种用于分配大量大小相同的小对象的技术。它可以极大加快内存分配/释放的速度。
内存池一旦初始化完成,内部的内存块大小将不能再做调整。每一个内存池其实就是一个链表,由于链表的大小全部相同,每次分配的时候,从链表中取出链头上第一个内存块,提供给申请者,每次释放内存,就把释放的内存重新加入链表即可。这种算法的优势是显而易见的,释放和分配内存都只需要O(1)的时间即可完成。当然也有很大的缺陷,只能分配固定的内存,对于不同大小的内存分配无法很好的满足。
下面就来看看rt_mempool这个类的相关成员: ```struct rt_mempool { struct rt_object parent; /*< inherit from rt_object /
void *start_address; /**< memory pool start */ rt_size_t size; /**< size of memory pool */ rt_size_t block_size; /**< size of memory blocks */ rt_uint8_t *block_list; /**< memory blocks list */ rt_size_t block_total_count; /**< numbers of memory block */ rt_size_t block_free_count; /**< numbers of free memory block */ rt_list_t suspend_thread; /**< threads pended on this resource */ rt_size_t suspend_thread_count; /**< numbers of thread pended on this resource */ };```
1.parent rt_object实例化,同样rt_mempool也是继承自rt_object
2.start_address 内存池起始地址
3.size 内存池总大小,size=(block_size + sizeof(uint8_t )) block_total_count
4.block_size 每个块的大小
5.block_list 空闲块所组成的列表
6.block_total_count 总内存块数量
7.block_free_count 空闲内存块数量
8.suspend_thread 由于等待空闲内存而挂起的线程列表
9.suspend_thread_count 挂起的线程总数
内存池内存分配算法相对来说比较简单,相关的函数如下: ```rt_err_t rt_mp_init(struct rt_mempool mp, const char name, void start, rt_size_t size, rt_size_t block_size); rt_err_t rt_mp_detach(struct rt_mempool mp); rt_mp_t rt_mp_create(const char *name, rt_size_t block_count, rt_size_t block_size); rt_err_t rt_mp_delete(rt_mp_t mp);
void rt_mp_alloc(rt_mp_t mp, rt_int32_t time); void rt_mp_free(void block);```
一、rt_mp_init与rt_mp_create ```rt_mp_t rt_mp_create(const char name, rt_size_t block_count, rt_size_t block_size) { rt_uint8_t block_ptr; struct rt_mempool *mp; register rt_size_t offset;
RT_DEBUG_NOT_IN_INTERRUPT; /* allocate object */ mp = (struct rt_mempool *)rt_object_allocate(RT_Object_Class_MemPool, name); /* allocate object failed */ if (mp == RT_NULL) return RT_NULL; /* initialize memory pool */ block_size = RT_ALIGN(block_size, RT_ALIGN_SIZE); mp->block_size = block_size; mp->size = (block_size + sizeof(rt_uint8_t *)) * block_count; /* allocate memory */ mp->start_address = rt_malloc((block_size + sizeof(rt_uint8_t *)) * block_count); if (mp->start_address == RT_NULL) { /* no memory, delete memory pool object */ rt_object_delete(&(mp->parent)); return RT_NULL; } mp->block_total_count = block_count; mp->block_free_count = mp->block_total_count; /* initialize suspended thread list */ rt_list_init(&(mp->suspend_thread)); mp->suspend_thread_count = 0; /* initialize free block list */ block_ptr = (rt_uint8_t *)mp->start_address; for (offset = 0; offset < mp->block_total_count; offset ++) { *(rt_uint8_t **)(block_ptr + offset * (block_size + sizeof(rt_uint8_t *))) = block_ptr + (offset + 1) * (block_size + sizeof(rt_uint8_t *)); } *(rt_uint8_t **)(block_ptr + (offset - 1) * (block_size + sizeof(rt_uint8_t *))) = RT_NULL; mp->block_list = block_ptr; return mp; }```
|