【rtthread内核系列】第五篇:内存分配

一、内存分配概念

计算机系统中,变量存放在ram中,只有在使用时才将它调入cpu运行,rtthread提供了两类内存分配方法:

  • 动态内存堆
  • 静态内存池。

动态内存堆根据系统资源的情况有3种分配算法:

  • 小内存管理算法:一般用于内存小于2M的设备
  • slab管理算法:近似多内存池的快速算法。
  • memheap算法:适用于存在多个内存堆的系统。

虽然采用的内存分配算法,但提供给应用程序的api完全相同。

二、动态内存分配api

//内存堆初始化:在相同初始化时执行。 这个函数会把参数begin_addr, end_addr 区域的内存空间作为内存堆来使用。
/*
begin_addr:内存堆起始地址
end_addr:内存堆结束地址
*/
void rt_system_heap_init(void* begin_addr, void* end_addr);

//memheap算法的内存堆初始化
/*
memheap:memheap句柄
name:内存堆名称
start_addr:内存堆起始地址
size:内存堆大小
*/
rt_err_t rt_memheap_init(struct rt_memheap *memheap,
                                const char *name,
                                void *start_addr,
                                rt_uint32_t size)

//分配内存
/*
nbytes:内存大小,单位:字节
返回:内存地址
*/
void *rt_malloc(rt_size_t nbytes);

//释放内存
/*
ptr:内存地址
*/
void rt_free (void *ptr);

//重新分配内存
/*
rmem:已分配的内存地址
newsize:重新分配的大小,原内容不变,缩小的情况后面数据被截断。
*/
void *rt_realloc(void *rmem, rt_size_t newsize);

//分配连续的多个内存
/*
count:内存块数量
size:每个内存块大小
*/
void *rt_calloc(rt_size_t count, rt_size_t size);

//设置内存分配完成钩子函数:内存分配完成执行设置的钩子回调函数
/*
hook:钩子函数指针
*/
void rt_malloc_sethook(void (*hook)(void *ptr, rt_size_t size));

//设置内存释放钩子函数
/*
hook:钩子函数指针
*/
void rt_free_sethook(void (*hook)(void *ptr));

三、内存池api

3.1 内存池概念

rtthread将内存池抽象成 rt_mempool。

3.2 内存池api

//创建内存池
/*
name:内存池名称
block_count:内存块数量
block_size:内存块大小
*/
rt_mp_t rt_mp_create(const char* name,
                            rt_size_t block_count,
                            rt_size_t block_size);
//删除内存池
/*
mp:内存池句柄
*/
rt_err_t rt_mp_delete(rt_mp_t mp);

//初始化内存池
/*
mp:内存池句柄
name:内存池名称
start:内存池起始地址
size:内存池大小
block_size:每个内存块大小
*/
rt_err_t rt_mp_init(rt_mp_t mp,
                        const char* name,
                        void *start, rt_size_t size,
                        rt_size_t block size);
                        
//内存池脱离
/*
mp:内存池句柄
*/
rt_err_t rt_mp_detach(rt_mp_t mp);

//分配内存
/*
mp:内存池句柄
time:等待分配超时时间
*/
void *rt_mp_alloc (rt_mp_t mp, rt_int32_t time);

//释放内存
/*
block:内存块地址
*/
void rt_mp_free (void *block);

四、内存分配示例

4.1 动态内存分配示例

/*
 * Copyright (c) 2006-2018, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2018-08-24     yangjie      the first version
 */

/*
 * 程序清单:动态内存管理例程
 *
 * 这个程序会创建一个动态的线程,这个线程会动态申请内存并释放
 * 每次申请更大的内存,当申请不到的时候就结束
 */
#include <rtthread.h>

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

/* 线程入口 */
void thread1_entry(void *parameter)
{
    
    
    int i;
    char *ptr = RT_NULL; /* 内存块的指针 */

    for (i = 0; ; i++)
    {
    
    
        /* 每次分配 (1 << i) 大小字节数的内存空间 */
        ptr = rt_malloc(1 << i);

        /* 如果分配成功 */
        if (ptr != RT_NULL)
        {
    
    
            rt_kprintf("get memory :%d byte\n", (1 << i));
            /* 释放内存块 */
            rt_free(ptr);
            rt_kprintf("free memory :%d byte\n", (1 << i));
            ptr = RT_NULL;
        }
        else
        {
    
    
            rt_kprintf("try to get %d byte memory failed!\n", (1 << i));
            return;
        }
    }
}

int dynmem_sample(void)
{
    
    
    rt_thread_t tid = RT_NULL;

    /* 创建线程1 */
    tid = rt_thread_create("thread1",
                           thread1_entry, RT_NULL,
                           THREAD_STACK_SIZE,
                           THREAD_PRIORITY,
                           THREAD_TIMESLICE);
    if (tid != RT_NULL)
        rt_thread_startup(tid);

    return 0;
}

/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(dynmem_sample, dynmem sample);

4.2 内存池分配示例

/*
 * Copyright (c) 2006-2018, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2018-08-24     yangjie      the first version
 */

/*
 * 程序清单:内存池例程
 *
 * 这个程序会创建一个静态的内存池对象,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;

    /* 初始化内存池对象 */
    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);

Supongo que te gusta

Origin blog.csdn.net/weixin_43810563/article/details/116722157
Recomendado
Clasificación