一、内存分配概念
计算机系统中,变量存放在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);