内存池的使用

内存池的使用

内存池介绍

动态内存堆可以分配任意大小的内存块,非常灵活和方便。但其存在明显的缺点:一是分配效率不高,在每次分配时,都要进行空闲内存块查找;二是容易产生内存碎片。
为了提高内存分配的效率,并且避免内存碎片,RT-Thread 提供了另外一种内存管理方法:内存池(Memory Pool)
内存池是一种内存分配方式,用于分配大量大小相同的小内存块。使用内存池可以极大地加快内存分配与释放的速度,且能尽量避免内存碎片化
RT-Thread的内存池支持线程挂起功能,当内存池中无空闲内存块时,申请线程会被挂起,直到内存池中有新的可用内存块,再将挂起的线程唤醒。基于这个特点内存池非常适合需要通过内存资源进行同步的场景。

内存池工作机制

内存池在创建时先从系统中获取一大块内存 (静态或动态),然后分成相同大小的多个小内存块,这些小内存块通过链表连接起来( 此链表也称为空闲链表)。线程每次申请分配内存块的时候,系统从空闲链表中取出链头上第一个内存块,提供给申请者

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aUUnNBtr-1627401699412)(C:\Users\在飞电脑\AppData\Roaming\Typora\typora-user-images\image-20210727231500890.png)]

内存池控制块

在RT-Thread中,内存池控制块是操作系统用于管理内存池的一个数据结构。

/* 在rtdef.h中对结构体的定义 */

#ifdef RT_USING_MEMPOOL
/**
 * Base structure of Memory pool object
 */
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 */
};
typedef struct rt_mempool *rt_mp_t;
#endif
struct rt_mempool static_mp			//定义静态邮箱
rt_mp_t dynamic_mp					//定义动态信号量

内存池的操作

初始化与脱离

//用于静态内存池
rt_err_t rt_mp_init(rt_mempool *mp, const char *name, void *start, rt_size_t size, rt_size_t block_size)
/* 内存块数目计算公式:block_count = size/(block_size(4的整数倍) + 4(指针大小)) */
rt_err_t rt_mp_detach(rt_mp_t mp)

创建和删除

//用于动态内存池
rt_mp_t rt_mp_create(const char *name, t_size_t block_count, rt_size_t block_size)
rt_err_t rt_mp_delete(rt_mp_t mp)

申请内存块

rt_err_t rt_mp_alloc(rt_mp_t mp, rt_uint32_t time);

释放内存块

rt_err_t rt_mp_free(void *block)

小例

代码

/*
 * 程序清单:内存池例程
 *
 * 这个程序会创建一个静态的内存池对象,2个动态线程。
 * 一个线程会试图从内存池中获得内存块,另一个线程释放内存块
 */
#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;

    /* 初始化内存池对象 */
    /* block_count = 4096 / (80 + 4) = 48 */
    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);

结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KnVQ76Iy-1627401699415)(C:\Users\在飞电脑\AppData\Roaming\Typora\typora-user-images\image-20210727233436033.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ewGTgLJq-1627401699416)(C:\Users\在飞电脑\AppData\Roaming\Typora\typora-user-images\image-20210727233443715.png)]在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值