20191012 (23)RT-Thread 内存管理

目的

1 了解 RT-Thread 内存管理的方式
2 了解动态内存堆管理 和 静态内存池管理


正文:

内存管理的特点

1 分配内存的时间必须确定
2 避免内存分配的碎片化问题
3 内存资源差异较大

RT-Thread 三种管理方式
1 小内存 小内存管理法 <2MB
2 大内存 slab 管理法
3 多内存 memheap 管理法

简单介绍:
slab 是 linux 一种内存分配机制,其特点就是针对经常分配并释放的对象,统一由 slab 管理;通俗而言,就是直接分配一个区域,并且规划了大小,需要使用的时候直接分配对应空闲区域地址即可,这样就避免了碎片化这个问题

注意:
1 不要在中断服务例程中分配或释放动态内存块


1 小内存
magic --》 0x1ea0 内存保护字,正常只有内存管理器会使用,如果被改写则认定内存被非法改写

used: 指出内存块是否已经分配

2 slab 管理算法
分配流程:
1 先检查 zone 链表是否为空,是则分配一个新的 zone
2 zone 非空,第一个 zone 节点必然有空闲块(否则不会存在在 zone 中)就取来使用
3 内存释放则需要将内存块链接到 zone 空闲内存块链表中
4 当 zone 空闲块到达一定数量之后,系统将会释放到页面分配器中

3 memheap 管理算法
将多个内存块,加入到 memheap_item 中进行粘合,形成一个完整的操作内存堆


内存堆的管理方式

申请内存 rt_malloc/realloc/calloc
释放内存 rt_free / rt_free_sethook

rt_realloc 裁剪/增加内存
rt_calloc 分配多内存块


内存池

作用:用于分配大量大小相同的小内存块,可以极大地加速内存分配与释放的速度,避免内存碎片化
内存池控制块由结构体 struct rt_mempool 表示。另外一种 C 表达方式 rt_mp_t,表示的是内存块句柄

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;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q3Ikh1dj-1570850646331)(en-resource://database/18640:0)]

管理方式依旧:

创建/初始化 rt_mp_create/init()
分配内存块 rt_mp_alloc()
释放内存块 rt_mp_free()
删除/脱离 rt_mp_delete/detach()

内存池块个数 = size / (block_size + 4 链表指针大小),计算结果取整数。例如:内存池数据区总大小 size 设为 4096 字节,内存块大小 block_size 设为 80 字节;则申请的内存块个数为 4096/ (80+4)= 48 个


#include <rtthread.h> 

static rt_uint8_t *ptr[50]; 
static rt_uint8_t mempool[4096]; 
static struct rt_mempool mp; 

#define THREAD_PRIORITY 25 
#define THREAD_STACK_SIZE 512 
#define THREAD_TIMESLICE 5 

/* 指向线程控制块的指针 */ 
static rt_thread_t tid1 = RT_NULL; 
static rt_thread_t tid2 = RT_NULL; 

/* 线程 1 入口 */ 
static void thread1_mp_alloc(void *parameter) { 
    int i; 
    for (i = 0 ; i < 50 ; i++) { 
        if (ptr[i] == RT_NULL) { 
        /* 试图申请内存块 50 次,当申请不到内存块时, 线程 1 挂起,转至线程 2 运行 */ 
            ptr[i] = rt_mp_alloc(&mp, RT_WAITING_FOREVER); 
            if (ptr[i] != RT_NULL) 
                rt_kprintf("allocate No.%d\n", i); 
        } 
    } 
}
/* 线程 2 入口,线程 2 的优先级比线程 1 低,应该线程 1 先获得执行。*/ 
static void thread2_mp_release(void *parameter) { 
    int i; 
    rt_kprintf("thread2 try to release block\n"); 
    for (i = 0; i < 50 ; i++) { /* 释放所有分配成功的内存块 */ 
        if (ptr[i] != RT_NULL) { 
            rt_kprintf("release block %d\n", i); 
            rt_mp_free(ptr[i]); 
            ptr[i] = RT_NULL; 
        } 
    }
} 

int mempool_sample(void) { 
    int i;
    for (i = 0; i < 50; i ++) 
        ptr[i] = RT_NULL; /* 初始化内存池对象 */ 
    rt_mp_init(&mp, "mp1", &mempool[0], sizeof(mempool), 80); /* 创建线程 1:申请内存池 */ 
    tid1 = rt_thread_create("thread1", thread1_mp_alloc, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE);

    if (tid1 != RT_NULL) 
        rt_thread_startup(tid1); 
    /* 创建线程 2:释放内存池 */ 
    tid2 = rt_thread_create("thread2", thread2_mp_release, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY + 1,THREAD_TIMESLICE); 
    if (tid2 != RT_NULL) 
        rt_thread_startup(tid2); 
    return 0; 
} 
/* 导出到 msh 命令列表中 */ 
MSH_CMD_EXPORT(mempool_sample, mempool sample);
发布了120 篇原创文章 · 获赞 27 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/qq_24890953/article/details/102517131