[FreeRTOS 基础知识] 堆


堆的概念

所谓的堆就是一块空间的内存,可以来管理这块内存。从这块内存中取出一部分然后再释放回去。


使用C语言实现 堆

char heap_buf[1024];            // 定义一个堆空间
int pos=0;                      // 当前位置

void *my_malloc(int size)
{
    int old_pos = pos;           // 记录旧位置
    pos += size;                 // 更新位置点
    return &heap_buf[old_pos];   // 返回旧位置地址
}

根据堆的概念写出上面的代码。定义出一块堆的空间heap_buf,可以在这块堆空间上任意申请,使用和释放空间。
使用Keil单步调试,对堆heap_buf申请和使用情况
在这里插入图片描述
根据单步调试情况可以看出:buf分配的起始地址就是heap_buf 堆空间起始地址,并且完成对堆空间的写入。


堆空间解析

使用上面的代码可以实现简单堆空间的申请和使用,但是这种简单的malloc函数没有办法释放空间。如下图所示
在这里插入图片描述
假如第一次使用my_malloc分配100字节空间buf1,第二次使用my_malloc分配100字节空间buf2
此时去释放空间buf1的空间my_free(buf1),只知道buf1的起始地址,却不知道应该释放多大的内存空间。 因此使用简单的malloc无法实现释放空间。

在操作系统中对堆空间的管理,在分配实际内存前有一段头部空间,其中存放分配这段内存的相关信息包括分配的空间大小。
因此使用malloc函数申请堆空间时, 实际在堆空间中分配两部分:头部信息+实际可操作的堆空间。malloc返回值是实际可操作的堆空间的起始地址。
使用free函数释放空间时, 会根据传入的地址(实际可操作的堆空间的起始地址)减去固定的头部大小,找到头部中这块申请的堆空间大小。从而释放空间。
在这里插入图片描述

假如将buf2释放掉后,整个堆空间的空闲区域有buf2头部信息+50字节+其他空闲区域。这时要申请100空间的内存,应该如何分配呢?
为了解决这个问题,引入链表来解决。链表基本形式如下:

// 定义全局链表
struct head
{
    int size;
    struct head *next_free;
}

struct head g_heap;
g_heap.size = 0;
g_heap.next_free = NULL;

初始状态, 在堆内存空闲区域会构建一个头部,表明当前堆空闲大小以及下一个堆空闲的位置。
在这里插入图片描述
分配100字节空间。 会先判断g_heap.next_free所指向的头部中size的大小,若大于申请的空间就会划分出两块,一块为分配的空间,另一块为空闲空间。
在这里插入图片描述
以此类推,继续分配出50字节和100字节的空间
在这里插入图片描述
当执行free(buf2)函数,释放50字节的空间时,流程如下:
1、先将buf2的地址减去8,查找头部信息中的size为50
2、释放50+8字节的空间。
3、g_heap.next_free所指向空闲空间头部中next_free就会指向buf2已经释放的起始地址(上图中绿色的开头)。

这样,当下一个malloc的时候,会先看g_heap.next_free所指向空闲空间头部中size。
若大于申请的大小就划分空间;
若小于申请的大小就继续判断next_free所指向的size大小。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bazinga bingo

您的鼓励就是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值