前言
本次主要介绍RT-Thread中另一种内存管理方式,内存堆。相对于内存池来说,内存池是一种静态内存管理方法,内存堆则是一种动态的管理方式。 基本数据结构
struct rt_memheap_item
{
rt_uint32_t magic;
struct rt_memheap * pool_ptr;
struct rt_memheap_item * next;
struct rt_memheap_item * prev;
struct rt_memheap_item * next_free;
struct rt_memheap_item * prev_free;
} ;
struct rt_memheap
{
struct rt_object parent;
void * start_addr;
rt_uint32_t pool_size;
rt_uint32_t available_size;
rt_uint32_t max_used_size;
struct rt_memheap_item * block_list;
struct rt_memheap_item * free_list;
struct rt_memheap_item free_header;
struct rt_semaphore lock;
} ;
创建
RT-Thread中要使用内存堆,首先要对其使能,即定义宏RT_USING_MEMHEAP 。之后调用rt_memheap_init 进行内存堆初始化。这里,若定义了宏RT_USING_MEMHEAP_AS_HEAP ,即使用内存堆的方式管理内存,则系统提供了函数rt_system_heap_init ,用于初始化一个默认的系统内存堆。
static struct rt_memheap _heap;
void rt_system_heap_init ( void * begin_addr, void * end_addr)
{
rt_memheap_init ( & _heap,
"heap" ,
begin_addr,
( rt_uint32_t ) end_addr - ( rt_uint32_t ) begin_addr) ;
}
而这个函数又是在系统启动 时rtthread_startup ,进行板级初始化时rt_hw_board_init 中调用的。
int rtthread_startup ( void )
{
. . .
rt_hw_board_init ( ) ;
. . .
return 0 ;
}
void rt_hw_board_init ( )
{
. . .
# if defined ( RT_USING_USER_MAIN) && defined ( RT_USING_HEAP)
rt_system_heap_init ( rt_heap_begin_get ( ) , rt_heap_end_get ( ) ) ;
# endif
. . .
}
# if defined ( RT_USING_USER_MAIN) && defined ( RT_USING_HEAP)
# define RT_HEAP_SIZE 1024
static uint32_t rt_heap[ RT_HEAP_SIZE] ;
RT_WEAK void * rt_heap_begin_get ( void )
{
return rt_heap;
}
RT_WEAK void * rt_heap_end_get ( void )
{
return rt_heap + RT_HEAP_SIZE;
}
# endif
回到rt_memheap_init 函数,此函数对用户传入的struct rt_memheap 进行初始化,这里,有几个宏,用于之后判断是否是空闲内存块,以下为源码:
# define RT_MEMHEAP_MAGIC 0x1ea01ea0
# define RT_MEMHEAP_MASK 0xfffffffe
# define RT_MEMHEAP_USED 0x01
# define RT_MEMHEAP_FREED 0x00
rt_err_t rt_memheap_init ( struct rt_memheap * memheap,
const char * name,
void * start_addr,
rt_size_t size)
{
struct rt_memheap_item * item;
RT_ASSERT ( memheap != RT_NULL) ;
rt_object_init ( & ( memheap-> parent) , RT_Object_Class_MemHeap, name) ;
memheap-> start_addr = start_addr;
memheap-> pool_size = RT_ALIGN_DOWN ( size, RT_ALIGN_SIZE) ;
memheap-> available_size = memheap-> pool_size - ( 2 * RT_MEMHEAP_SIZE) ;
memheap-> max_used_size = memheap-> pool_size - memheap-> available_size;
item = & ( memheap-> free_header) ;
item-> magic = RT_MEMHEAP_MAGIC;
item-> pool_ptr = memheap;
item-> next = RT_NULL;
item-> prev = RT_NULL;
item-> next_free = item;
item-> prev_free = item;
memheap-> free_list = item;
item = ( struct rt_memheap_item * ) start_addr;
item-> magic = RT_MEMHEAP_MAGIC;
item-> pool_ptr = memheap;
item-> next = ( struct rt_memheap_item * )
( ( rt_uint8_t * ) item + memheap-> available_size + RT_MEMHEAP_SIZE) ;
item-> prev = item-> next;
item-> next_free = memheap-> free_list-> next_free;
item-> prev_free = memheap-> free_list;
memheap-> block_list = item;
memheap-> free_list-> next_free-> prev_free = item;
memheap-> free_list-> next_free = item;
item = item-> next;
item-> magic = RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED;
item-> pool_ptr = memheap;
item-> next = ( struct rt_memheap_item * ) start_addr;
item-> prev = ( struct rt_memheap_item * ) start_addr;
item-> next_free = item-> prev_free = RT_NULL;
rt_sem_init ( & ( memheap-> lock) , name, 1 , RT_IPC_FLAG_FIFO) ;
RT_DEBUG_LOG ( RT_DEBUG_MEMHEAP,
( "memory heap: start addr 0x%08x, size %d, free list header 0x%08x\n" ,
start_addr, size, & ( memheap-> free_header) ) ) ;
return RT_EOK;
}
删除
rt_memheap_detach 主要将指定的内存堆中内核中分离,这里不会进行释放操作。
rt_err_t rt_memheap_detach ( struct rt_memheap * heap)
{
RT_ASSERT ( heap) ;
RT_ASSERT ( rt_object_get_type ( & heap-> parent) == RT_Object_Class_MemHeap) ;
RT_ASSERT ( rt_object_is_systemobject ( & heap-> parent) ) ;
rt_object_detach ( & ( heap-> lock. parent. parent) ) ;
rt_object_detach ( & ( heap-> parent) ) ;
return RT_EOK;
}
分配
void * rt_memheap_alloc ( struct rt_memheap * heap, rt_size_t size)
{
rt_err_t result;
rt_uint32_t free_size;
struct rt_memheap_item * header_ptr;
RT_ASSERT ( heap != RT_NULL) ;
RT_ASSERT ( rt_object_get_type ( & heap-> parent) == RT_Object_Class_MemHeap) ;
size = RT_ALIGN ( size, RT_ALIGN_SIZE) ;
if ( size < RT_MEMHEAP_MINIALLOC)
size = RT_MEMHEAP_MINIALLOC;
RT_DEBUG_LOG ( RT_DEBUG_MEMHEAP, ( "allocate %d on heap:%8.*s" ,
size, RT_NAME_MAX, heap-> parent. name) ) ;
if ( size < heap-> available_size)
{
free_size = 0 ;
result = rt_sem_take ( & ( heap-> lock) , RT_WAITING_FOREVER) ;
if ( result != RT_EOK)
{
rt_set_errno ( result) ;
return RT_NULL;
}
header_ptr = heap-> free_list-> next_free;
while ( header_ptr != heap-> free_list && free_size < size)
{
free_size = MEMITEM_SIZE ( header_ptr) ;
if ( free_size < size)
{
header_ptr = header_ptr-> next_free;
}
}
if ( free_size >= size)
{
if ( free_size >= ( size + RT_MEMHEAP_SIZE + RT_MEMHEAP_MINIALLOC) )
{
struct rt_memheap_item * new_ptr;
new_ptr = ( struct rt_memheap_item * )
( ( ( rt_uint8_t * ) header_ptr) + size + RT_MEMHEAP_SIZE) ;
RT_DEBUG_LOG ( RT_DEBUG_MEMHEAP,
( "split: block[0x%08x] nextm[0x%08x] prevm[0x%08x] to new[0x%08x]\n" ,
header_ptr,
header_ptr-> next,
header_ptr-> prev,
new_ptr) ) ;
new_ptr-> magic = RT_MEMHEAP_MAGIC;
new_ptr-> pool_ptr = heap;
new_ptr-> prev = header_ptr;
new_ptr-> next = header_ptr-> next;
header_ptr-> next-> prev = new_ptr;
header_ptr-> next = new_ptr;
header_ptr-> next_free-> prev_free = header_ptr-> prev_free;
header_ptr-> prev_free-> next_free = header_ptr-> next_free;
header_ptr-> next_free = RT_NULL;
header_ptr-> prev_free = RT_NULL;
new_ptr-> next_free = heap-> free_list-> next_free;
new_ptr-> prev_free = heap-> free_list;
heap-> free_list-> next_free-> prev_free = new_ptr;
heap-> free_list-> next_free = new_ptr;
RT_DEBUG_LOG ( RT_DEBUG_MEMHEAP, ( "new ptr: next_free 0x%08x, prev_free 0x%08x\n" ,
new_ptr-> next_free,
new_ptr-> prev_free) ) ;
heap-> available_size = heap-> available_size -
size -
RT_MEMHEAP_SIZE;
if ( heap-> pool_size - heap-> available_size > heap-> max_used_size)
heap-> max_used_size = heap-> pool_size - heap-> available_size;
}
else
{
heap-> available_size = heap-> available_size - free_size;
if ( heap-> pool_size - heap-> available_size > heap-> max_used_size)
heap-> max_used_size = heap-> pool_size - heap-> available_size;
RT_DEBUG_LOG ( RT_DEBUG_MEMHEAP,
( "one block: block[0x%08x], next_free 0x%08x, prev_free 0x%08x\n" ,
header_ptr,
header_ptr-> next_free,
header_ptr-> prev_free) ) ;
header_ptr-> next_free-> prev_free = header_ptr-> prev_free;
header_ptr-> prev_free-> next_free = header_ptr-> next_free;
header_ptr-> next_free = RT_NULL;
header_ptr-> prev_free = RT_NULL;
}
header_ptr-> magic |= RT_MEMHEAP_USED;
rt_sem_release ( & ( heap-> lock) ) ;
RT_DEBUG_LOG ( RT_DEBUG_MEMHEAP,
( "alloc mem: memory[0x%08x], heap[0x%08x], size: %d\n" ,
( void * ) ( ( rt_uint8_t * ) header_ptr + RT_MEMHEAP_SIZE) ,
header_ptr,
size) ) ;
return ( void * ) ( ( rt_uint8_t * ) header_ptr + RT_MEMHEAP_SIZE) ;
}
rt_sem_release ( & ( heap-> lock) ) ;
}
RT_DEBUG_LOG ( RT_DEBUG_MEMHEAP, ( "allocate memory: failed\n" ) ) ;
return RT_NULL;
}
重分配
void * rt_memheap_realloc ( struct rt_memheap * heap, void * ptr, rt_size_t newsize)
{
rt_err_t result;
rt_size_t oldsize;
struct rt_memheap_item * header_ptr;
struct rt_memheap_item * new_ptr;
RT_ASSERT ( heap) ;
RT_ASSERT ( rt_object_get_type ( & heap-> parent) == RT_Object_Class_MemHeap) ;
if ( newsize == 0 )
{
rt_memheap_free ( ptr) ;
return RT_NULL;
}
newsize = RT_ALIGN ( newsize, RT_ALIGN_SIZE) ;
if ( newsize < RT_MEMHEAP_MINIALLOC)
newsize = RT_MEMHEAP_MINIALLOC;
if ( ptr == RT_NULL)
{
return rt_memheap_alloc ( heap, newsize) ;
}
header_ptr = ( struct rt_memheap_item * )
( ( rt_uint8_t * ) ptr - RT_MEMHEAP_SIZE) ;
oldsize = MEMITEM_SIZE ( header_ptr) ;
if ( newsize > oldsize)
{
void * new_ptr;
struct rt_memheap_item * next_ptr;
result = rt_sem_take ( & ( heap-> lock) , RT_WAITING_FOREVER) ;
if ( result != RT_EOK)
{
rt_set_errno ( result) ;
return RT_NULL;
}
next_ptr = header_ptr-> next;
RT_ASSERT ( next_ptr > header_ptr) ;
if ( ! RT_MEMHEAP_IS_USED ( next_ptr) )
{
rt_int32_t nextsize;
nextsize = MEMITEM_SIZE ( next_ptr) ;
RT_ASSERT ( next_ptr > 0 ) ;
if ( nextsize + oldsize > newsize + RT_MEMHEAP_MINIALLOC)
{
heap-> available_size = heap-> available_size - ( newsize - oldsize) ;
if ( heap-> pool_size - heap-> available_size > heap-> max_used_size)
heap-> max_used_size = heap-> pool_size - heap-> available_size;
RT_DEBUG_LOG ( RT_DEBUG_MEMHEAP,
( "remove block: block[0x%08x], next_free 0x%08x, prev_free 0x%08x" ,
next_ptr,
next_ptr-> next_free,
next_ptr-> prev_free) ) ;
next_ptr-> next_free-> prev_free = next_ptr-> prev_free;
next_ptr-> prev_free-> next_free = next_ptr-> next_free;
next_ptr-> next-> prev = next_ptr-> prev;
next_ptr-> prev-> next = next_ptr-> next;
next_ptr = ( struct rt_memheap_item * ) ( ( char * ) ptr + newsize) ;
RT_DEBUG_LOG ( RT_DEBUG_MEMHEAP,
( "new free block: block[0x%08x] nextm[0x%08x] prevm[0x%08x]" ,
next_ptr,
next_ptr-> next,
next_ptr-> prev) ) ;
next_ptr-> magic = RT_MEMHEAP_MAGIC;
next_ptr-> pool_ptr = heap;
next_ptr-> prev = header_ptr;
next_ptr-> next = header_ptr-> next;
header_ptr-> next-> prev = next_ptr;
header_ptr-> next = next_ptr;
next_ptr-> next_free = heap-> free_list-> next_free;
next_ptr-> prev_free = heap-> free_list;
heap-> free_list-> next_free-> prev_free = next_ptr;
heap-> free_list-> next_free = next_ptr;
RT_DEBUG_LOG ( RT_DEBUG_MEMHEAP, ( "new ptr: next_free 0x%08x, prev_free 0x%08x" ,
next_ptr-> next_free,
next_ptr-> prev_free) ) ;
rt_sem_release ( & ( heap-> lock) ) ;
return ptr;
}
}
rt_sem_release ( & ( heap-> lock) ) ;
new_ptr = ( void * ) rt_memheap_alloc ( heap, newsize) ;
if ( new_ptr != RT_NULL)
{
rt_memcpy ( new_ptr, ptr, oldsize < newsize ? oldsize : newsize) ;
rt_memheap_free ( ptr) ;
}
return new_ptr;
}
if ( newsize + RT_MEMHEAP_SIZE + RT_MEMHEAP_MINIALLOC >= oldsize)
return ptr;
result = rt_sem_take ( & ( heap-> lock) , RT_WAITING_FOREVER) ;
if ( result != RT_EOK)
{
rt_set_errno ( result) ;
return RT_NULL;
}
new_ptr = ( struct rt_memheap_item * )
( ( ( rt_uint8_t * ) header_ptr) + newsize + RT_MEMHEAP_SIZE) ;
RT_DEBUG_LOG ( RT_DEBUG_MEMHEAP,
( "split: block[0x%08x] nextm[0x%08x] prevm[0x%08x] to new[0x%08x]\n" ,
header_ptr,
header_ptr-> next,
header_ptr-> prev,
new_ptr) ) ;
new_ptr-> magic = RT_MEMHEAP_MAGIC;
new_ptr-> pool_ptr = heap;
new_ptr-> prev = header_ptr;
new_ptr-> next = header_ptr-> next;
header_ptr-> next-> prev = new_ptr;
header_ptr-> next = new_ptr;
if ( ! RT_MEMHEAP_IS_USED ( new_ptr-> next) )
{
struct rt_memheap_item * free_ptr;
free_ptr = new_ptr-> next;
heap-> available_size = heap-> available_size - MEMITEM_SIZE ( free_ptr) ;
RT_DEBUG_LOG ( RT_DEBUG_MEMHEAP,
( "merge: right node 0x%08x, next_free 0x%08x, prev_free 0x%08x\n" ,
header_ptr, header_ptr-> next_free, header_ptr-> prev_free) ) ;
free_ptr-> next-> prev = new_ptr;
new_ptr-> next = free_ptr-> next;
free_ptr-> next_free-> prev_free = free_ptr-> prev_free;
free_ptr-> prev_free-> next_free = free_ptr-> next_free;
}
new_ptr-> next_free = heap-> free_list-> next_free;
new_ptr-> prev_free = heap-> free_list;
heap-> free_list-> next_free-> prev_free = new_ptr;
heap-> free_list-> next_free = new_ptr;
RT_DEBUG_LOG ( RT_DEBUG_MEMHEAP, ( "new free ptr: next_free 0x%08x, prev_free 0x%08x\n" ,
new_ptr-> next_free,
new_ptr-> prev_free) ) ;
heap-> available_size = heap-> available_size + MEMITEM_SIZE ( new_ptr) ;
rt_sem_release ( & ( heap-> lock) ) ;
return ptr;
}
释放
void rt_memheap_free ( void * ptr)
{
rt_err_t result;
struct rt_memheap * heap;
struct rt_memheap_item * header_ptr, * new_ptr;
rt_uint32_t insert_header;
if ( ptr == RT_NULL) return ;
insert_header = 1 ;
new_ptr = RT_NULL;
header_ptr = ( struct rt_memheap_item * )
( ( rt_uint8_t * ) ptr - RT_MEMHEAP_SIZE) ;
RT_DEBUG_LOG ( RT_DEBUG_MEMHEAP, ( "free memory: memory[0x%08x], block[0x%08x]\n" ,
ptr, header_ptr) ) ;
RT_ASSERT ( ( header_ptr-> magic & RT_MEMHEAP_MASK) == RT_MEMHEAP_MAGIC) ;
RT_ASSERT ( header_ptr-> magic & RT_MEMHEAP_USED) ;
RT_ASSERT ( ( header_ptr-> next-> magic & RT_MEMHEAP_MASK) == RT_MEMHEAP_MAGIC) ;
heap = header_ptr-> pool_ptr;
RT_ASSERT ( heap) ;
RT_ASSERT ( rt_object_get_type ( & heap-> parent) == RT_Object_Class_MemHeap) ;
result = rt_sem_take ( & ( heap-> lock) , RT_WAITING_FOREVER) ;
if ( result != RT_EOK)
{
rt_set_errno ( result) ;
return ;
}
header_ptr-> magic &= ~ RT_MEMHEAP_USED;
heap-> available_size = heap-> available_size + MEMITEM_SIZE ( header_ptr) ;
if ( ! RT_MEMHEAP_IS_USED ( header_ptr-> prev) )
{
RT_DEBUG_LOG ( RT_DEBUG_MEMHEAP, ( "merge: left node 0x%08x\n" ,
header_ptr-> prev) ) ;
heap-> available_size = heap-> available_size + RT_MEMHEAP_SIZE;
( header_ptr-> prev) -> next = header_ptr-> next;
( header_ptr-> next) -> prev = header_ptr-> prev;
header_ptr = header_ptr-> prev;
insert_header = 0 ;
}
if ( ! RT_MEMHEAP_IS_USED ( header_ptr-> next) )
{
heap-> available_size = heap-> available_size + RT_MEMHEAP_SIZE;
new_ptr = header_ptr-> next;
RT_DEBUG_LOG ( RT_DEBUG_MEMHEAP,
( "merge: right node 0x%08x, next_free 0x%08x, prev_free 0x%08x\n" ,
new_ptr, new_ptr-> next_free, new_ptr-> prev_free) ) ;
new_ptr-> next-> prev = header_ptr;
header_ptr-> next = new_ptr-> next;
new_ptr-> next_free-> prev_free = new_ptr-> prev_free;
new_ptr-> prev_free-> next_free = new_ptr-> next_free;
}
if ( insert_header)
{
header_ptr-> next_free = heap-> free_list-> next_free;
header_ptr-> prev_free = heap-> free_list;
heap-> free_list-> next_free-> prev_free = header_ptr;
heap-> free_list-> next_free = header_ptr;
RT_DEBUG_LOG ( RT_DEBUG_MEMHEAP,
( "insert to free list: next_free 0x%08x, prev_free 0x%08x\n" ,
header_ptr-> next_free, header_ptr-> prev_free) ) ;
}
rt_sem_release ( & ( heap-> lock) ) ;
}
其他
若进行了系统内存堆,则rt_malloc 、rt_calloc 、rt_realloc 、rt_free 将被定义为如下:
void * rt_malloc ( rt_size_t size)
{
void * ptr;
ptr = rt_memheap_alloc ( & _heap, size) ;
if ( ptr == RT_NULL)
{
struct rt_object * object;
struct rt_list_node * node;
struct rt_memheap * heap;
struct rt_object_information * information;
information = rt_object_get_information ( RT_Object_Class_MemHeap) ;
RT_ASSERT ( information != RT_NULL) ;
for ( node = information-> object_list. next;
node != & ( information-> object_list) ;
node = node-> next)
{
object = rt_list_entry ( node, struct rt_object , list) ;
heap = ( struct rt_memheap * ) object;
RT_ASSERT ( heap) ;
RT_ASSERT ( rt_object_get_type ( & heap-> parent) == RT_Object_Class_MemHeap) ;
if ( heap == & _heap)
continue ;
ptr = rt_memheap_alloc ( heap, size) ;
if ( ptr != RT_NULL)
break ;
}
}
return ptr;
}
void rt_free ( void * rmem)
{
rt_memheap_free ( rmem) ;
}
void * rt_realloc ( void * rmem, rt_size_t newsize)
{
void * new_ptr;
struct rt_memheap_item * header_ptr;
if ( rmem == RT_NULL)
return rt_malloc ( newsize) ;
if ( newsize == 0 )
{
rt_free ( rmem) ;
return RT_NULL;
}
header_ptr = ( struct rt_memheap_item * )
( ( rt_uint8_t * ) rmem - RT_MEMHEAP_SIZE) ;
new_ptr = rt_memheap_realloc ( header_ptr-> pool_ptr, rmem, newsize) ;
if ( new_ptr == RT_NULL && newsize != 0 )
{
new_ptr = rt_malloc ( newsize) ;
if ( new_ptr != RT_NULL && rmem != RT_NULL)
{
rt_size_t oldsize;
oldsize = MEMITEM_SIZE ( header_ptr) ;
if ( newsize > oldsize)
rt_memcpy ( new_ptr, rmem, oldsize) ;
else
rt_memcpy ( new_ptr, rmem, newsize) ;
rt_free ( rmem) ;
}
}
return new_ptr;
}
void * rt_calloc ( rt_size_t count, rt_size_t size)
{
void * ptr;
rt_size_t total_size;
total_size = count * size;
ptr = rt_malloc ( total_size) ;
if ( ptr != RT_NULL)
{
rt_memset ( ptr, 0 , total_size) ;
}
return ptr;
}
rt_malloc 中若进行内存分配失败,则会从系统内存堆对象中遍历,尝试从中分配。用户不需要考虑从单一内存堆分配内存失败的情况。rt_realloc 中若进行内存重分配失败,则会调用rt_malloc 尝试获取新内存。用户不需要考虑内存重分配失败后尝试分配的处理。