全部文档
概述 硬件支持 快速开发指南 内核 驱动 通用组件 专业组件 常见问题

内存堆管理


OneOS提供了两种内存堆管理算法,包括first-fit管理算法、buddy管理算法。

first-fit管理算法,主要由以下特点:

  • 将内存以chunk的形式进行管理,而chunk的基本单位是8字节;
  • 申请内存的最小单位为8字节,有效的减少内存碎片问题;
  • 内部查找空闲区基于位图和哈希桶算法,有效提高内存空闲区查找速度;
  • 适用于内存资源比较少比较小的系统(本身管理算法和每次以8字节为单位申请本身浪费空间较少)。

buddy算法是为了核心内存管理能够快速响应请求,尽可能地在提高内存利用率的同时减少内存碎片的一种算法,主要有以下特点:

  • 伙伴算法是按2的幂次方大小进行分配内存块,避免把大的内存块拆的太碎,更重要的是使分配和释放过程迅速;
  • 所需内存大小不是2的幂次方,会有部分页面浪费;
  • 拆分和合并涉及到较多的链表和位图操作,开销比较大;
  • 适用于不太在意内存浪费而又需要内存申请释放效率敏感的内存较大的系统。

OneOS把程序链接后剩余的内存空间放置于系统堆中,应用程序可以直接使用os_malloc/os_free来申请内存和释放内存,对于链接了标准的C库的系统可以直接使用malloc/free实现内存堆管理。

对于一块连续的内存作为系统堆,用于可以首先使用os_sys_heap_init初始化系统堆管理对象,然后通过os_sys_heap_add指定管理内存的起始地址,长度和算法(first-fit管理算法或者buddy管理算法)。如果还有另外一段内存(和之前的添加的空间不连续),用户可以再次使用os_sys_heap_add把这段内存加入到系统内存堆中,这样实现了管理部连续内存空间。需要说明的是第一次添加的内存区域和第二次添加的内存可以使用不同的内存堆管理算法。在用户申请内存时总是先从第一个内存区域查找,如果没有可用区域,再从第二个内存区域查找。多个内存区域的系统堆如下图所示:

应用程序在某些场景下需要有自己的堆(后续简称用户堆)。可以首先使用os_memheap_init初始化用户堆管理对象,我们可以使用os_malloc申请一片内存(也可以直接找一片系统堆空间外的内存),然后通过os_memheap_add指定管理内存的起始地址,长度和算法(first-fit管理算法或者buddy管理算法)。后续应用程序可以直接使用os_memheap_alloc/os_memheap_free来申请内存和释放内存。用户堆和系统堆同样可以添加多个内存区域。

注意事项: 因为内存堆管理器要满足多任务使用,存在多任务的互斥问题,所以中断服务例程中不能使用分配或释放动态内存块。因为它可能会引起当前上下文被挂起等待。

重要定义及数据结构

内存算法枚举

enum os_mem_alg
{
#ifdef OS_USING_ALG_FIRSTFIT
    OS_MEM_ALG_FIRSTFIT,
#endif
#ifdef OS_USING_ALG_BUDDY
    OS_MEM_ALG_BUDDY,
#endif
    OS_MEM_ALG_DEFAULT          /*Use default memory algorithm */
};
内存算法枚举 说明
OS_MEM_ALG_FIRSTFIT first-fit管理算法
OS_MEM_ALG_BUDDY buddy管理算法
OS_MEM_ALG_DEFAULT 默认算法,系统支持的第一个算法

内存堆结构体

struct os_memheap
{
    struct heap_mem            *h_mem;
    os_uint8_t                  object_inited;
    char                        name[OS_NAME_MAX + 1];
    os_list_node_t              resource_node;          /* Node in resource list */
};
内存堆对象成员变量 说明
h_mem 该内存堆的第一个内存区域控制块的指针
object_inited 标记该内存堆对象是否已初始化
name 内存堆的名字,最大字符长度不超过OS_NAME_MAX
resource_node 资源节点,用于将该内存堆对象挂到内存堆的全局资源链表头
struct os_meminfo 
{
    os_size_t                   mem_total;
    os_size_t                   mem_used;
    os_size_t                   mem_maxused;
};
typedef struct os_meminfo os_meminfo_t;
内存堆信息成员变量 说明
mem_total 内存堆对象总空间大小
mem_used 内存堆对象已分配空间大小
mem_maxused 内存堆对象最大分配空间大小

API列表

接口 说明
os_sys_heap_init 系统堆初始化接口,系统初始化时调用
os_sys_heap_add 添加一个内存区域到系统堆,系统初始化时调用
os_malloc 从系统堆上分配指定大小的内存
os_aligned_malloc 从系统堆上分配指定对齐长度、指定大小的内存
os_realloc 更改已经分配的内存空间
os_calloc 分配连续的多个内存块,分配成功后初始化内存为0
os_free 释放内存
os_memory_info 返回系统堆对象信息
os_memory_check 校验系统堆对象
os_memheap_init 初始化一个内存堆对象
os_memheap_add 向内存堆对象添加一个内存区域,可指定管理算法
os_memheap_alloc 在os_memheap_init()初始化的内存堆上分配一块内存
os_memheap_aligned_alloc 在os_memheap_init()初始化的内存堆上分配指定对齐长度、指定大小的内存
os_memheap_realloc 调整通过os_memheap_alloc()分配的内存
os_memheap_free 释放通过os_memheap_alloc()分配的内存
os_memheap_info 返回内存堆对象信息
os_memheap_check 校验内存堆对象

os_sys_heap_init

该函数为初始化系统堆,必须在系统初始化时调用此接口,函数原型如下:

void os_sys_heap_init(void);
参数 说明
返回 说明

os_sys_heap_add

该函数添加一个内存区域到系统堆,系统初始化时调用,函数原型如下:

os_err_t os_sys_heap_add(void *start_addr, os_size_t size, enum os_mem_alg alg);
参数 说明
start_addr 内存区域首地址
size 内存区域空间大小
alg 此内存区域管理算法,可选OS_MEM_ALG_FIRSTFIT(first-fit管理算法)、OS_MEM_ALG_BUDDY(buddy管理算法)
返回 说明
OS_EOK 添加成功
OS_EINVAL 指定的内存区域和其他内存堆管理的区域重叠
OS_ENOMEM 指定的内存区域太小,不能满足内存堆使用最小空间

os_malloc

该函数从系统堆上分配指定大小的内存,函数原型如下:

void *os_malloc(os_size_t size);
参数 说明
size 分配内存的大小
返回 说明
非OS_NULL 分配成功,返回分配的内存地址
OS_NULL 分配失败

os_aligned_malloc

该函数分配由allign指定的字节对齐的内存,allign的大小为2的幂,函数原型如下:

void *os_aligned_malloc(os_size_t align, os_size_t size);
参数 说明
align 对齐的大小,allign的大小必须为2的幂
size 分配内存的大小
返回 说明
非OS_NULL 分配成功,返回分配的内存地址
OS_NULL 分配失败

os_realloc

该函数重新分配内存,并保留原有数据(若缩小内存,会截断数据),函数原型如下:

void *os_realloc(void *ptr, os_size_t size);
参数 说明
ptr 原有已分配内存的地址
size 新内存大小
返回 说明
非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_memory_info

该函数返回系统堆对象信息,包括内存大小、内存使用大小、最大使用大小,函数原型如下:

void os_memory_info(os_meminfo_t *info);
参数 说明
info 返回系统堆对象信息
返回 说明

os_memory_check

该函数校验系统堆对象,主要校验已分配内存和空闲内存的组织关系时候正确,函数原型如下:

os_err_t os_memory_check(void);
参数 说明
返回 说明
OS_EOK 校验成功
OS_ERROR 校验失败

os_memheap_init

该函数初始化一个内存堆对象,函数原型如下:

os_err_t os_memheap_init(os_memheap_t *heap, const char *name);
参数 说明
heap 内存堆对象句柄
name 名字
返回 说明
OS_EOK 初始化成功
OS_EINVAL 内存对象重复初始化

os_memheap_add

该函数添加一个内存区域到一个已经被初始化的内存堆对象中,添加的内存区域需要指定管理算法,函数原型如下:

os_err_t os_memheap_add(os_memheap_t *heap, void *start_addr, os_size_t size, enum os_mem_alg alg);
参数 说明
heap 内存堆对象句柄
start_addr 内存区域首地址
size 内存区域空间大小
alg 此内存区域管理算法,可选OS_MEM_ALG_FIRSTFIT(first-fit管理算法)、OS_MEM_ALG_BUDDY(buddy管理算法)
返回 说明
OS_EOK 添加成功
OS_EINVAL 指定的内存区域和其他内存堆管理的区域重叠
OS_ENOMEM 指定的内存区域太小,不能满足内存堆使用最小空间

os_memheap_alloc

该函数在指定内存对象上分配内存,函数原型如下:

void *os_memheap_alloc(struct os_memheap *heap, os_size_t size);
参数 说明
heap 内存堆对象句柄
size 分配内存的大小
返回 说明
非OS_NULL 分配成功,返回分配的内存地址
OS_NULL 分配失败

os_memheap_aligned_alloc

该函数在指定内存对象上分配由allign指定的字节对齐的内存,allign的大小为2的幂,函数原型如下:

void *os_memheap_aligned_alloc(os_memheap_t *heap, os_size_t align, os_size_t size);
参数 说明
heap 内存堆对象句柄
align 对齐的大小,allign的大小必须为2的幂
size 分配内存的大小
返回 说明
非OS_NULL 分配成功,返回分配的内存地址
OS_NULL 分配失败

os_memheap_realloc

该函数在指定内存对象上重新分配内存,并保留原有数据(若缩小内存,会截断数据),函数原型如下:

void *os_memheap_realloc(os_memheap_t *heap, void *ptr, os_size_t size);
参数 说明
heap 内存堆对象句柄
ptr 待调整的内存地址
size 待重新分配的新大小
返回 说明
非OS_NULL 调整成功,返回分配的内存地址
OS_NULL 调整失败

os_memheap_free

该函数释放由os_memheap_alloc()或os_memheap_realloc()申请的内存,函数原型如下:

void os_memheap_free(os_memheap_t *heap, void *ptr);
参数 说明
heap 内存堆对象句柄
ptr 待释放内存的地址
返回 说明

os_memheap_info

该函数返回内存堆对象信息,包括内存大小、内存使用大小、最大使用大小,函数原型如下:

void os_memheap_info(os_memheap_t *heap, os_meminfo_t *info);
参数 说明
heap 内存堆对象句柄
info 返回系统堆对象信息
返回 说明

os_memheap_check

该函数校验内存堆对象,主要校验已分配内存和空闲内存的组织关系时候正确,函数原型如下:

os_err_t os_memheap_check(os_memheap_t *heap);
参数 说明
返回 说明
OS_EOK 校验成功
OS_ERROR 校验失败

配置选项

OneOS在使用内存堆时提供了一些功能选项和裁剪的配置,具体配置如下图所示:

配置项 说明
Enable System-Memory-Heap OneOS使能系统堆功能
Enable FIRSTFIT memory algorithm OneOS支持firstfit管理算法
Enable BUDDY memory algorithm OneOS支持buddy管理算法

使用示例

内存堆管理使用示例

本例配置为使能系统堆并采用firstfit管理算法。展示了使用os_malloc和os_free申请和释放内存,使用os_realloc重新分配内存,注意os_realloc重新分配内存的地址可能与原始地址不同

#include <oneos_config.h>
#include <dlog.h>
#include <os_errno.h>
#include <shell.h>
#include <os_memory.h>

#define TEST_TAG        "TEST"

#define TEST_MALLOC_TIMES   20

void sys_heap_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(sys_heap_sample, sys_heap_sample, "test sys heap");

运行结果如下:

sh>sys_heap_sample
W/TEST: malloc memory:2000351c size:1
W/TEST: free memory  :2000351c size:1
W/TEST: malloc memory:2000351c size:2
W/TEST: free memory  :2000351c size:2
W/TEST: malloc memory:2000351c size:4
W/TEST: free memory  :2000351c size:4
W/TEST: malloc memory:2000351c size:8
W/TEST: free memory  :2000351c size:8
W/TEST: malloc memory:2000351c size:16
W/TEST: free memory  :2000351c size:16
W/TEST: malloc memory:2000351c size:32
W/TEST: free memory  :2000351c size:32
W/TEST: malloc memory:2000351c size:64
W/TEST: free memory  :2000351c size:64
W/TEST: malloc memory:2000351c size:128
W/TEST: free memory  :2000351c size:128
W/TEST: malloc memory:2000351c size:256
W/TEST: free memory  :2000351c size:256
W/TEST: malloc memory:2000351c size:512
W/TEST: free memory  :2000351c size:512
W/TEST: malloc memory:2000351c size:1024
W/TEST: free memory  :2000351c size:1024
W/TEST: malloc memory:2000351c size:2048
W/TEST: free memory  :2000351c size:2048
W/TEST: malloc memory:20004b44 size:4096
W/TEST: free memory  :20004b44 size:4096
W/TEST: malloc memory:20004b44 size:8192
W/TEST: free memory  :20004b44 size:8192
W/TEST: malloc memory:20004b44 size:16384
W/TEST: free memory  :20004b44 size:16384
W/TEST: malloc memory:20004b44 size:32768
W/TEST: free memory  :20004b44 size:32768
W/TEST: malloc memory:20004b44 size:65536
W/TEST: free memory  :20004b44 size:65536
W/TEST: try to get 131072 byte memory failed!
W/TEST: malloc memory:2000351c size:100
W/TEST: realloc memory:2000351c size:1
W/TEST: realloc memory:2000351c size:2
W/TEST: realloc memory:2000351c size:4
W/TEST: realloc memory:20003524 size:8
W/TEST: realloc memory:20003534 size:16
W/TEST: realloc memory:2000354c size:32
W/TEST: realloc memory:20003574 size:64
W/TEST: realloc memory:200035bc size:128
W/TEST: realloc memory:20003644 size:256
W/TEST: realloc memory:2000374c size:512
W/TEST: realloc memory:20003954 size:1024
W/TEST: realloc memory:20004b44 size:2048
W/TEST: realloc memory:2000534c size:4096
W/TEST: realloc memory:20006354 size:8192
W/TEST: realloc memory:2000835c size:16384
W/TEST: realloc memory:2000c364 size:32768
W/TEST: try to realloc 65536 byte memory failed!

memheap管理算法接口使用示例

本例配置为使能系统堆并采用firstfit管理算法。开始时使用标准的堆管理接口分配出一块内存,然后使用初始化一个内存堆对象,使用firstfit管理算法来管理这段内存区域 ,之后就可以使用memheap的接口来分配和释放这块内存。

#include <oneos_config.h>
#include <dlog.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 user_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 = 2048;
    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");
    if (err == OS_EOK)
    {
        LOG_W(TEST_TAG, "init memheap_test successfully");
    }
    else
    {
        LOG_W(TEST_TAG, "failed to init memheap_test");
        return;
    }

    err = os_memheap_add(&memheap_test, start_addr, size, OS_MEM_ALG_FIRSTFIT);
    if (err == OS_EOK)
    {
        LOG_W(TEST_TAG, "add memory zone to memheap_test, start_addr:%p size:%d", start_addr, size);
    }
    else
    {
        LOG_W(TEST_TAG, "failed to add memory zone.");
        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(&memheap_test, 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 = 64;
    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;
    }


    size = 68;
    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(&memheap_test, ptr_old);
    }

    size = 60;
    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(&memheap_test, ptr_old);
    }


    if(ptr_new)
    {
        os_memheap_free(&memheap_test, ptr_new);
    }

    os_free(start_addr);
}

SH_CMD_EXPORT(user_heap_sample, user_heap_sample, "test user heap");

运行结果如下:

sh>user_heap_sample
W/TEST: init memheap_test successfully
W/TEST: add memory zone to memheap_test, start_addr:2000353c size:2048
W/TEST: memheap_alloc:200035dc size:1
W/TEST: memheap_free :200035dc size:1
W/TEST: memheap_alloc:200035dc size:2
W/TEST: memheap_free :200035dc size:2
W/TEST: memheap_alloc:200035dc size:4
W/TEST: memheap_free :200035dc size:4
W/TEST: memheap_alloc:200035dc size:8
W/TEST: memheap_free :200035dc size:8
W/TEST: memheap_alloc:200035dc size:16
W/TEST: memheap_free :200035dc size:16
W/TEST: memheap_alloc:200035dc size:32
W/TEST: memheap_free :200035dc size:32
W/TEST: memheap_alloc:200035dc size:64
W/TEST: memheap_free :200035dc size:64
W/TEST: memheap_alloc:200035dc size:128
W/TEST: memheap_free :200035dc size:128
W/TEST: memheap_alloc:200035dc size:256
W/TEST: memheap_free :200035dc size:256
W/TEST: memheap_alloc:200035dc size:512
W/TEST: memheap_free :200035dc size:512
W/TEST: memheap_alloc:200035dc size:1024
W/TEST: memheap_free :200035dc size:1024
W/TEST: try to memheap_alloc 2048 byte failed
W/TEST: memheap_realloc memory:200035dc size:64
W/TEST: memheap_realloc memory:200035dc size:68
W/TEST: memheap_realloc memory:200035dc size:60

results matching ""

    No results matching ""