RTT的内存管理篇——野火RTT讲解

野火RTT第24章内存管理
2018年12月29日
10:48

操作系统只给出内存管理函数原型,也就是函数声明。但是具体如何实现它是不管的。
可靠性要求高的采用静态内存,内存使用效率低,而一般的也许使用动态内存可以提高内存使用效率。

没有内存管理会出现内存碎片问题。

内存碎片问题:不断分配和释放时导致内存对齐不同,就会出现很多小块的内存且地址是不连续的,在某个时刻系统会因为没有连续地址比较大的内存块而无法分配内存,导致线程崩溃,甚至影响整个系统崩溃。这就是内存泄露。所以为了避免这种情况的出现,需要内存分配算法。

但是这些分配算法只有一部分是嵌入式实时操作系统能用,因为有条件:实时性,就是说分配算法要满足嵌入式的时间的实时性,分配的太慢影响系统的实时性,这种算法就滚蛋。

RTT的内存管理就是根据不同嵌入式应用场景可选择不同的相适应的内存管理算法。
内存管理就是选择内存管理算法的。
这些算法分为:静态内存管理和动态内存管理。
动态内存管理分两类:小内存管理算法和大内存管理算法。

内存管理算法的选择:根据产品。
内存管理算法选择标准参考:静态内存特点,动态内存特点。
静态内存特点:知道确定的内存占用,效率比动态内存效率高,但利用率没动态内存高。比如静态你开辟了100个字节空间,但你往往用不到100个。而动态内存是按需分配,我需要100个就去分配100个,百分百用到。但动态会出现碎片。

静态内存管理:内存池memory pool,大量相同的内存块组成的内存空间,而且是预先定义好的,一旦初始化,那些相同大小内存块就固定大小了,不能改变了。

动态内存管理:小内存管理一般用于小于2M的内存系统空间。而SLAB用于大内存管理提供近似内存池管理的快速算法。这两种算法的API接口相同,只是由宏定义来决定开启哪个,或者都不开启——关掉动态内存管理。小内存动态管理算法和SLAB算法选其一,由宏定义开启。
注意:在中断中不要分配和释放动态内存块,可能会造成上下文切换。

小内存动态管理算法:每块小内存都有个数据头用来存放管理信息的,否则怎么管理这一块?标识下这块小内存干啥了,是空闲还是被用了。它占用12字节,分为magic区域、used区域和链表(指向下一块内存)。这样方便管理。相当于你给每块用的没用的内存都打上标记,这样先标记然后才能去管理呀!它的管理思路:动态分配的时候根据你动态分配的大小,然后在空闲内存块里查找大于你需要大小的内存块,然后将其分割成使用的内存块和空闲块,并将其放到使用链表和控制链表下。当释放时,查找被释放块前后有没有空闲块有的话合并成一个空闲块,这样就尽量避免碎片。

静态内存管理第一个函数:create是在创建的动态堆里面开辟一片静态内存,也就是把动态开辟的堆当成静态内存来使用。而静态内存初始化init函数是将预先定义好的静态内存进行初始化。
它们不同的是:第一,create动态创建静态内存池控制块返回其指针,也就是说只需要定义控制块指针来存放控制块指针,刚开始不知道这个控制块指针的。也是从堆里面分配的。而init需要将内存池控制块预先定义好,地址定义好了,传到init。第二,create动态开辟堆作为静态内存池,而init的静态内存池是预先定义好的。从这比较来看,create好一点,利用率高呀!create是动态创建的静态内存池,按需分配。
相同的:其他的都一样。每块内存块排列操作一样,每块内存块:内存块大小+内存链表大小。

第三,从传入的参数来看。ceate因为是动态创建所以形参最少,3个,内存池控制块指针,内存池的内存块块总数,每个内存块大小(字节)。init就多啦,预先定义好的内存池控制块变量的地址,预先定义好的内存池首地址,内存池总大小(字节),内存池的每个内存块大小(字节)。

alloc申请静态内存池的内存块函数:内存块已经初始化时固定了。传入参数:内存池控制块地址、等待时间。
没有可用内存块,挂起当前线程,超时等待。返回用户真正能读写操作的内存块地址,偏移了4字节。其中:把下个空闲的块地址放到内存池控制块里的链表里,也就是更新链表指向地址,单向链表。而更新用的内存块链表指向内存池控制块,所有的已用过内存块都指向内存池控制块,因为静态内存不能真正释放。

静态内存块释放free函数:不是真正的释放,静态内存无法释放,只能改变其单向链表的指向空闲链表。过程:找到内存池控制块,可用控制计数加1,将空闲快插入到挂内存控制块的链表根节点下。

你可能感兴趣的:(rt-thread)