RTT学习笔记之内存池管理(静态内存池)

来源:互联网 发布:k均值聚类算法opencv 编辑:程序博客网 时间:2024/05/11 17:15
RTT学习笔记之内存池管理(静态内存池)

     在计算系统中,变量、中间数据一般存放在系统存储空间中,当实际使用时才从存储空间调入到中央处理器内部进行运算。存储空间,按照存储方式来分类可以分为两种,内部存储空间和外部存储空间。内部存储空间通常访问速度比较快,能够随机访问(按照变量地址)。RTT编程指南中主要介绍了内部存储空间的管理。实时系统中由于它对时间要求的严格性,其中的内存分配往往要比通用操作系统苛刻得多:
• 首先,分配内存的时间必须是确定性的。一般内存管理算法是搜索一个适当范围去寻找适合长度的空闲内存块。这个适当,造成了搜索时间的不确定性,这对于实时系统是不可接受的,因为实时系统必须要保证内存块的分配过程在可预测的确定时间内完成,否则实时任务在对外部事响应也将变得时间不可确定性,例如一个处理数据的例子:当一个外部数据达到时(通过传感器或网络数据包),为了把它提交给上层的任务进行处理,它可能会先申请一块内存,把数据块的地址附加上,还可能有,数据长度以及一些其他信息附加在一起(放在一个结构体中),然后提交给上层任务。内存申请是当中的一个组成环节,如果因为使用的内存占用比较零乱,从而操作系统需要搜索一个不确定性长度队列寻找适合的内存,那么申请时间将变得不可确定(可能搜索了1次,也可能搜索了若干次才能找到匹配的空间),进而对整个响应时间产生不可确定性。如果此时是一次导弹
袭击,估计很可能会灰飞烟灭了!
• 其次,随着使用的内存分块被释放,整个内存区域会产生越来越多的碎片,从总体上来说,系统中还有足够的空闲内存,但因为它们非连续性,不能组成一块连续的完整内存块,从而造成程序不能申请到内存。对于通用系统而言,这种不恰当的内存分配算法可以通过重新启动系统来解决(每个月或者数个月进行一次),但是这个对于可能需要数年工作于野外的嵌入式系统来说是不可接受的,他们通常需要连续不断地运行下去。
• 最后,嵌入式系统的资源环境也不是都相同,有些系统中资源比较紧张,只有数十KB的内存可供分配,而有些系统则存在数MB的内存。
     RT-Thread操作系统在内存管理上,根据上层应用及系统资源的不同,有针对性的提供了数种内存分配管理算法:静态分区内存管理及动态内存管理。动态内存管理又更加可用内存多少划分为两种情况,一种是针对小内存块的分配管理,一种是针对大内存块的分配管理。这里主要总结一下静态内存池的管理。

一、静态内存池的工作模式

     上图是内存池管理结构示意图。内存池( Memory Pool)是一种用于分配大量大小相同的小对象的技术。它可以极大加快内存分配/释放过程。内存池在创建时向系统申请一大块内存,然后分成同样大小的多个小内存块,形成链表连接起来(此链表也称为空闲链表)。每次分配的时候,从空闲链表中取出头上一块,提供给申请者。如上图所示,物理内存中可以有多个大小不同的内存池,一个内存池由多个空闲内存块组成,内核用它们来进行内存管理。当一个内存池对象被创建时,内存池对象就被分配了内存池控制块:内存池名,内存缓冲区,内存块大小,块数以及一个等待线程队列。内核负责给内存池分配内存池对象控制块,它同时也接收用户线程传入的参数,像内存块大小以及块数,由这些来确定内存池对象所需内存大小,当获得了这些信息后,内核就可以从内存堆或者线程私有内存空间中为内存池分配内存。内存池一旦初始化完成,内部的内存块大小将不能再做调整。

二、静态内存池控制块
/*** Base structure of Memory pool object*/struct rt_mempool{    struct rt_object parent;                           /**< 继承内核对象控制块 */    void            *start_address;                     /**< 内存池起始地址 */    rt_size_t        size;                                   /**< 内存池大小 */    rt_size_t        block_size;                         /**< 块大小 */    rt_uint8_t      *block_list;                        /**< 块链表 */    rt_size_t        block_total_count;             /**< 内存块总数量 */    rt_size_t        block_free_count;              /**< 可用内存块数量 */    rt_list_t        suspend_thread;                 /**< 等待资源而挂起的线程 */    rt_size_t        suspend_thread_count;     /**< 等待资源而挂起的线程数量 */};typedef struct rt_mempool *rt_mp_t;        /**< 内存池句柄 */
三、简单实例
#include <rtthread.h>#include "finsh.h"struct rt_thread thread1;       /** 线程控制块     */         struct rt_thread thread2;       /** 线程控制块 */char thread1_stack[512];      /** 线程栈 */char thread2_stack[512];      /** 线程栈 */char mempool[4096];           /** 内存池数据存放区域 */struct rt_mempool mp;        /** 内存池控制块 */char *ptr[48];                       /** 测试用指针分配头 */void thread1_entry(void* parameter){     int i;     while(1)     {          for (i = 0; i < 48; i++)/** 分配48个内存块 */          {               rt_kprintf("allocate No.%d\n", i);               ptr[i] = rt_mp_alloc(&mp, RT_WAITING_FOREVER);          }        rt_thread_delay(100);     }}void thread2_entry(void *parameter){     int i;     while(1)     {                   for (i = 0 ; i < 48; i ++)/** 释放48个已经分配的内存块 */          {               if (ptr[i] != RT_NULL)               {                    rt_kprintf("release block %d\n", i);                    rt_mp_free(ptr[i]);                    ptr[i] = RT_NULL;               }          }        rt_thread_delay(100);     }}int rt_mempool_init(void){     int i;     for (i = 0; i < 48; i ++)    {               ptr[i] = RT_NULL;    }     /** 初始化一个内存池对象,每个内存块的大小是80个字节 */     rt_mp_init(&mp, "mp1", &mempool[0], sizeof(mempool), 80);     rt_thread_init(&thread1, "thread1", thread1_entry, RT_NULL, &thread1_stack[0], sizeof(thread1_stack), 20, 10);     rt_thread_init(&thread2, "thread2", thread2_entry, RT_NULL, &thread2_stack[0], sizeof(thread2_stack), 25, 7);     rt_thread_startup(&thread1);     rt_thread_startup(&thread2);     return 0;}int tc_mempool_simple(){     rt_mempool_init();     return 0;}FINSH_FUNCTION_EXPORT(tc_mempool_simple, a Memory pool example);/** 输出函数命令到finsh shell中 */
四、说明及运行结果
1、静态内存池初始化
rt_mp_init(&mp, "mp1", &mempool[0], sizeof(mempool), 80);
初始化一个静态内存池,起始地址为&mempool[0],大小为4096,每个内存块大小为80。
block_total_count = 4096/(80+sizeof(rt_uint8_t *))= 48;
2、申请和释放
创建两个线程,一个用于内存块申请,另一个用于内存块释放
内存块申请:
ptr[i] = rt_mp_alloc(&mp, RT_WAITING_FOREVER);
申请成功后会返回内存块的首地址。
内存块释放:
rt_mp_free(ptr[i]);ptr[i] = NULL;
3、运行结果
0 0
原创粉丝点击