内存堆管理
简介
内存堆管理可以在当前资源满足的前提下,根据用户的需求分配任意大小的内存,当用户不再使用时,可以释放回堆中。本操作系统提供了几种内存管理算法,包括小内存管理算法、slab管理算法和memheap管理算法。
小内存算法在最开始时是一块完整的大内存。分配内存实际上就是寻找第一个大于等于实际需求(申请大小加数据头大小)的空闲块并分割出来,剩余部分还回给堆管理系统。释放内存时,也会把释放的内存还回给堆管理系统,相邻有空闲块时会合并在一起。随着内存的不断分配和释放,原始的大内存被分成了多个大小不一的使用内存块和空闲内存块。每个内存块包含两部分,一是用于内存管理的数据头(包括链表指针、使用标志等),另外一部分为实际返回的可供用户使用的空间。
slab管理算法是由slab分配器修改而来,在运行过程中,会把内存分成不同尺寸的zone,每个zone中划分成多个相同大小的内存块。相同大小的内存块链接在一个zone的链表中,而不同的zone则通过数组管理。最多包含72种zone,一次最大可以分配16K的空间,超出时直接从页分配器中分配。
memheap管理算法可用于系统中含有多个地址不连续的内存堆,即用户可以将多个(地址可不连续)memheap合在一起使用。其具体分配算法和小内存算法比较相似。
内存堆管理有一套统一的接口,如os_malloc、 os_free等;memheap管理另外还有一套接口,如os_memheap_alloc、os_memheap_free。
内存堆管理可以有以下配置组合:
(1)OS_USING_HEAP + OS_USING_MEM_SMALL,采用小内存管理算法,操作接口为os_system_heap_init、os_malloc、 os_free等;
(2)OS_USING_HEAP + OS_USING_MEM_SLAB,采用slab管理算法,操作接口为os_system_heap_init、os_malloc、 os_free等;
(3)OS_USING_HEAP + OS_USING_MEM_HEAP + OS_USING_MEM_HEAP_AS_HEAP,采用memheap算法,操作接口为os_system_heap_init、os_malloc、 os_free等(此种配置下,若有多个不连续的堆,第一个堆使用os_system_heap_init初始化后,其它堆使用os_memheap_init初始化,之后使用os_malloc时系统会先到第一个堆上去分配,若分配不到则会去其它堆上分配);
(4)OS_USING_HEAP + OS_USING_MEM_SMALL + OS_USING_MEM_HEAP,采用小内存管理算法,操作接口为os_system_heap_init、os_malloc、 os_free等;但是同时支持memheap算法,使用os_memheap_init初始化的内存区域,操作接口为os_memheap_alloc、os_memheap_free等;
(5)OS_USING_HEAP + OS_USING_MEM_SLAB + OS_USING_MEM_HEAP,采用slab管理算法,操作接口为os_system_heap_init、os_malloc、 os_free等;但是同时支持memheap算法,使用os_memheap_init初始化的内存区域,操作接口为os_memheap_alloc、os_memheap_free等。
API列表
接口 | 说明 |
---|---|
os_system_heap_init | 堆初始化接口,系统初始化时调用 |
os_malloc | 从内存堆上分配指定大小的内存 |
os_realloc | 重新分配内存,并保留原数据 |
os_calloc | 分配连续的多个内存块 |
os_free | 释放内存 |
os_malloc_align | 分配由align指定的字节对齐的内存 |
os_free_align | 释放由os_malloc_align()分配的内存 |
os_memheap_init | 用memheap管理算法初始化一块内存 |
os_memheap_deinit | 反初始化memheap管理算法的内存 |
os_memheap_alloc | 在os_memheap_init()初始化的内存块上分配一块内存 |
os_memheap_realloc | 调整通过os_memheap_alloc()分配的内存 |
os_memheap_free | 释放通过os_memheap_alloc()分配的内存 |
os_system_heap_init
该函数为内存堆管理的初始化接口,使用内存堆管理时,必须在系统初始化时调用此接口,函数原型如下:
void os_system_heap_init(void *begin_addr, void *end_addr);
参数 | 说明 |
---|---|
begin_addr | 内存堆的起始地址 |
end_addr | 内存堆的结束地址 |
返回 | 说明 |
无 | 无 |
os_malloc
该函数从内存堆上分配指定大小的内存,函数原型如下:
void *os_malloc(os_size_t nbytes);
参数 | 说明 |
---|---|
nbytes | 分配内存的大小 |
返回 | 说明 |
非OS_NULL | 分配成功,返回分配的内存地址 |
OS_NULL | 分配失败 |
os_realloc
该函数重新分配内存,并保留原有数据(若缩小内存,会截断数据),函数原型如下:
void *os_realloc(void *ptr, os_size_t nbytes);
参数 | 说明 |
---|---|
ptr | 原有已分配内存的地址 |
nbytes | 新内存大小 |
返回 | 说明 |
非OS_NULL | 重新分配成功,返回调整之后的内存地址,此地址可能与原有地址不同 |
OS_NULL | 重新分配失败 |
os_calloc
该函数分配连续的多个内存块,并初始化为0,函数原型如下:
void *os_calloc(os_size_t count, os_size_t size);
参数 | 说明 |
---|---|
count | 元素的个数 |
size | 每个元素的字节数 |
返回 | 说明 |
非OS_NULL | 分配成功,且内存区域初始化为0 |
OS_NULL | 分配失败 |
os_free
该函数释放由os_malloc/os_realloc/os_calloc等分配的内存,函数原型如下:
void os_free(void *ptr);
参数 | 说明 |
---|---|
ptr | 待释放内存的地址 |
返回 | 说明 |
无 | 无 |
os_malloc_align
该函数分配由allign指定的字节对齐的内存,allign的大小本身按照4对齐,函数原型如下:
void *os_malloc_align(os_size_t size, os_size_t align);
参数 | 说明 |
---|---|
size | 分配内存的大小 |
align | 对齐的大小,allign本身按照4对齐;例如:若align是3,则申请内存的首地址按照4对齐;若allign是5,则申请内存的首地址按照8字节对齐 |
返回 | 说明 |
非OS_NULL | 分配成功,返回对齐的首地址 |
OS_NULL | 分配失败 |
os_free_align
该函数释放由os_malloc_align()分配的内存,函数原型如下:
void os_free_align(void *ptr);
参数 | 说明 |
---|---|
ptr | 待释放内存的地址 |
返回 | 说明 |
无 | 无 |
os_memheap_init
该函数采用memheap管理算法初始化一块内存,函数原型如下:
os_err_t os_memheap_init(struct os_memheap *memheap,
const char *name,
void *start_addr,
os_size_t size);
参数 | 说明 |
---|---|
memheap | memheap句柄 |
name | 名字 |
start_addr | 起始地址 |
size | memheap大小 |
返回 | 说明 |
OS_EOK | 初始化成功 |
os_memheap_deinit
该函数反初始化内存,与os_memheap_init()匹配使用,函数原型如下:
os_err_t os_memheap_deinit(struct os_memheap *heap);
参数 | 说明 |
---|---|
heap | memheap句柄 |
返回 | 说明 |
OS_EOK | 反初始化成功 |
os_memheap_alloc
该函数在指定memheap上分配内存,函数原型如下:
void *os_memheap_alloc(struct os_memheap *heap, os_size_t size);
参数 | 说明 |
---|---|
heap | memheap句柄 |
size | 分配内存的大小 |
返回 | 说明 |
非OS_NULL | 分配成功,返回分配的内存地址 |
OS_NULL | 分配失败 |
os_memheap_realloc
该函数调整原有分配内存的大小,函数原型如下:
void *os_memheap_realloc(struct os_memheap *heap, void *ptr, os_size_t newsize);
参数 | 说明 |
---|---|
heap | memheap句柄 |
ptr | 待调整的内存地址 |
newsize | 待重新分配的新大小 |
返回 | 说明 |
非OS_NULL | 调整成功,返回分配的内存地址 |
OS_NULL | 调整失败 |
os_memheap_free
该函数释放由os_memheap_alloc()或os_memheap_realloc()申请的内存,函数原型如下:
void os_memheap_free(void *ptr);
参数 | 说明 |
---|---|
ptr | 待释放内存的地址 |
返回 | 说明 |
无 | 无 |
使用示例
内存堆管理使用示例
本例配置为OS_USING_HEAP + OS_USING_MEM_SMALL,即采用小内存管理算法。展示了使用os_malloc和os_free申请和释放内存,使用os_realloc重新分配内存,注意os_realloc重新分配内存的地址可能与原始地址不同
#include <oneos_config.h>
#include <os_dbg.h>
#include <os_errno.h>
#include <shell.h>
#include <os_memory.h>
#define TEST_TAG "TEST"
#define TEST_MALLOC_TIMES 20
void memory_sample(void)
{
os_uint32_t i = 0;
os_uint32_t size = 0;
void *ptr = OS_NULL;
void *ptr_new = OS_NULL;
void *ptr_old = OS_NULL;
for (i = 0; i < TEST_MALLOC_TIMES; i++)
{
size = (1 << i);
ptr = os_malloc(size);
if (ptr)
{
LOG_W(TEST_TAG, "malloc memory:%p size:%d", ptr, size);
os_free(ptr);
LOG_W(TEST_TAG, "free memory :%p size:%d", ptr, size);
ptr = OS_NULL;
}
else
{
LOG_W(TEST_TAG, "try to get %d byte memory failed!", size);
break;
}
}
ptr_new = os_malloc(100);
if (ptr_new)
{
LOG_W(TEST_TAG, "malloc memory:%p size:%d", ptr_new, 100);
}
else
{
LOG_W(TEST_TAG, "try to get %d byte memory failed!", 100);
}
for (i = 0; i < TEST_MALLOC_TIMES; i++)
{
size = (1 << i);
ptr_old = ptr_new;
ptr_new = os_realloc(ptr_old, size);
if (ptr_new)
{
LOG_W(TEST_TAG, "realloc memory:%p size:%d", ptr_new, size);
}
else
{
LOG_W(TEST_TAG, "try to realloc %d byte memory failed!", size);
os_free(ptr_old);
break;
}
}
if (ptr_new)
{
os_free(ptr_new);
}
}
SH_CMD_EXPORT(test_memory, memory_sample, "test memory");
运行结果如下:
sh />test_memory
W/TEST: malloc memory:20007800 size:1
W/TEST: free memory :20007800 size:1
W/TEST: malloc memory:20007800 size:2
W/TEST: free memory :20007800 size:2
W/TEST: malloc memory:20007800 size:4
W/TEST: free memory :20007800 size:4
W/TEST: malloc memory:20007800 size:8
W/TEST: free memory :20007800 size:8
W/TEST: malloc memory:20007800 size:16
W/TEST: free memory :20007800 size:16
W/TEST: malloc memory:20007800 size:32
W/TEST: free memory :20007800 size:32
W/TEST: malloc memory:20007800 size:64
W/TEST: free memory :20007800 size:64
W/TEST: malloc memory:20007800 size:128
W/TEST: free memory :20007800 size:128
W/TEST: malloc memory:20007800 size:256
W/TEST: free memory :20007800 size:256
W/TEST: malloc memory:20007800 size:512
W/TEST: free memory :20007800 size:512
W/TEST: malloc memory:20007800 size:1024
W/TEST: free memory :20007800 size:1024
W/TEST: malloc memory:20007800 size:2048
W/TEST: free memory :20007800 size:2048
W/TEST: malloc memory:20007800 size:4096
W/TEST: free memory :20007800 size:4096
W/TEST: malloc memory:20007800 size:8192
W/TEST: free memory :20007800 size:8192
W/TEST: malloc memory:20007800 size:16384
W/TEST: free memory :20007800 size:16384
W/TEST: malloc memory:20007800 size:32768
W/TEST: free memory :20007800 size:32768
W/TEST: malloc memory:20007800 size:65536
W/TEST: free memory :20007800 size:65536
E/MSMALL: no memory
W/TEST: try to get 131072 byte memory failed!
W/TEST: malloc memory:20007800 size:100
W/TEST: realloc memory:20007800 size:1
W/TEST: realloc memory:20007800 size:2
W/TEST: realloc memory:20007800 size:4
W/TEST: realloc memory:20007814 size:8
W/TEST: realloc memory:20007830 size:16
W/TEST: realloc memory:20007800 size:32
W/TEST: realloc memory:20007830 size:64
W/TEST: realloc memory:20007880 size:128
W/TEST: realloc memory:20007910 size:256
W/TEST: realloc memory:20007a20 size:512
W/TEST: realloc memory:20007c30 size:1024
W/TEST: realloc memory:20008040 size:2048
W/TEST: realloc memory:20008850 size:4096
W/TEST: realloc memory:20009860 size:8192
W/TEST: realloc memory:2000b870 size:16384
W/TEST: realloc memory:2000f880 size:32768
W/TEST: try to realloc 65536 byte memory failed!
memheap管理算法接口使用示例
本例配置为OS_USING_HEAP + OS_USING_MEM_SMALL + OS_USING_MEM_HEAP,即采用小内存管理算法。开始时使用标准的堆管理接口分配出一块内存,然后使用memheap管理算法的接口来初始化这块内存,之后就可以使用memheap的接口来分配和释放这块内存
#include <oneos_config.h>
#include <os_dbg.h>
#include <os_errno.h>
#include <shell.h>
#include <os_memory.h>
#define TEST_TAG "TEST"
#define TEST_MALLOC_TIMES 20
static struct os_memheap memheap_test;
void memory_heap_sample(void)
{
void *ptr = OS_NULL;
void *ptr_new = OS_NULL;
void *ptr_old = OS_NULL;
void *start_addr = OS_NULL;
os_uint32_t size = 2000;
os_err_t err;
os_uint32_t i = 0;
start_addr = os_malloc(size);
if (!start_addr)
{
return;
}
err = os_memheap_init(&memheap_test, "memheap1", start_addr, size);
if (err == OS_EOK)
{
LOG_W(TEST_TAG, "init memheap_test, start_addr:%p size:%d", start_addr, size);
}
else
{
LOG_W(TEST_TAG, "failed to init memheap_test");
return;
}
for (i = 0; i < TEST_MALLOC_TIMES; i++)
{
size = (1 << i);
ptr = os_memheap_alloc(&memheap_test, size);
if (ptr)
{
LOG_W(TEST_TAG, "memheap_alloc:%p size:%d", ptr, size);
os_memheap_free(ptr);
LOG_W(TEST_TAG, "memheap_free :%p size:%d", ptr, size);
ptr = OS_NULL;
}
else
{
LOG_W(TEST_TAG, "try to memheap_alloc %d byte failed", size);
break;
}
}
size = 100;
ptr_new = os_memheap_alloc(&memheap_test, size);
if (ptr_new)
{
LOG_W(TEST_TAG, "memheap_realloc memory:%p size:%d", ptr_new, size);
}
else
{
LOG_W(TEST_TAG, "try to memheap_alloc %d byte memory failed!", size);
return;
}
for (i = 0; i < TEST_MALLOC_TIMES; i++)
{
size = (1 << i);
ptr_old = ptr_new;
ptr_new = os_memheap_realloc(&memheap_test, ptr_old, size);
if (ptr_new)
{
LOG_W(TEST_TAG, "memheap_realloc memory:%p size:%d", ptr_new, size);
}
else
{
LOG_W(TEST_TAG, "try to memheap_realloc %d byte memory failed!", size);
os_memheap_free(ptr_old);
break;
}
}
if(ptr_new)
{
os_memheap_free(ptr_new);
}
os_memheap_deinit(&memheap_test);
os_free(start_addr);
}
SH_CMD_EXPORT(test_memory_heap, memory_heap_sample, "test memory heap");
运行结果如下:
sh />test_memory_heap
W/TEST: init memheap_test, start_addr:20007888 size:2000
W/TEST: memheap_alloc:200078a0 size:1
W/TEST: memheap_free :200078a0 size:1
W/TEST: memheap_alloc:200078a0 size:2
W/TEST: memheap_free :200078a0 size:2
W/TEST: memheap_alloc:200078a0 size:4
W/TEST: memheap_free :200078a0 size:4
W/TEST: memheap_alloc:200078a0 size:8
W/TEST: memheap_free :200078a0 size:8
W/TEST: memheap_alloc:200078a0 size:16
W/TEST: memheap_free :200078a0 size:16
W/TEST: memheap_alloc:200078a0 size:32
W/TEST: memheap_free :200078a0 size:32
W/TEST: memheap_alloc:200078a0 size:64
W/TEST: memheap_free :200078a0 size:64
W/TEST: memheap_alloc:200078a0 size:128
W/TEST: memheap_free :200078a0 size:128
W/TEST: memheap_alloc:200078a0 size:256
W/TEST: memheap_free :200078a0 size:256
W/TEST: memheap_alloc:200078a0 size:512
W/TEST: memheap_free :200078a0 size:512
W/TEST: memheap_alloc:200078a0 size:1024
W/TEST: memheap_free :200078a0 size:1024
W/TEST: try to memheap_alloc 2048 byte failed
W/TEST: memheap_realloc memory:200078a0 size:100
W/TEST: memheap_realloc memory:200078a0 size:1
W/TEST: memheap_realloc memory:200078a0 size:2
W/TEST: memheap_realloc memory:200078a0 size:4
W/TEST: memheap_realloc memory:200078a0 size:8
W/TEST: memheap_realloc memory:200078a0 size:16
W/TEST: memheap_realloc memory:200078a0 size:32
W/TEST: memheap_realloc memory:200078a0 size:64
W/TEST: memheap_realloc memory:200078a0 size:128
W/TEST: memheap_realloc memory:200078a0 size:256
W/TEST: memheap_realloc memory:200078a0 size:512
W/TEST: memheap_realloc memory:200078a0 size:1024
W/TEST: try to memheap_realloc 2048 byte memory failed!