FreeRTOS解析:Mem - 内存管理

FreeRTOS解析:Mem - 内存管理

受博客限制,如果您想获得更好的阅读体验,请前往https://github.com/Nrusher/FreeRTOS-Book或者https://gitee.com/nrush/FreeRTOS-Book下载PDF版本阅读,如果您觉得本文不错也可前往star,以示对作者的鼓励。如发现问题欢迎交流。

FreeRTOS提供了5种不同的内存管理策略以应对不同的应用场景,本章将对这5种不同的内存管理策略的实现进行分析。(本章中部分图未画画出堆上字节对齐处理细节,请自行理解)

heap_1.c

heap_1.c所实现的内存管理方法十分简单,其可以使用pvPortMalloc()函数来申请内存,一旦申请成功了,便无法被释放。其实现大致可以用一句话概括,**在堆空间剩余时,按需分割出内存,并记录已用的内存大小。**heap_1.c使用的内存管理算法虽然简单,但对于许多嵌入式应用场景是适用且有效的。

在heap_1.c中,堆被定义为一个大数组,并使用变量xNextFreeByte记录已用内存大小

    static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
    static size_t xNextFreeByte = ( size_t ) 0;

核心代码pvPortMalloc()函数实现如下

    void *pvPortMalloc( size_t xWantedSize )
    {
   
    void *pvReturn = NULL;
    static uint8_t *pucAlignedHeap = NULL;
    
        /* 如果对齐字节数不为1,则对请求的字节数做调整 */
        #if( portBYTE_ALIGNMENT != 1 )
        {
   
            if( xWantedSize & portBYTE_ALIGNMENT_MASK )
            {
   
                xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
            }
        }
        #endif

        /* 挂起任务 */
        vTaskSuspendAll();
        {
   
            if( pucAlignedHeap == NULL )
            {
   
                /* 确保堆的起始地址是按字节对齐的(与操作可能会使地址值减小,因此使用&ucHeap[portBYTE_ALIGNMENT]作为起始地址) */
                pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) &ucHeap[ portBYTE_ALIGNMENT ] ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );
            }
    
            /* 检查是否有足够的空间分配 */
            if( ( ( xNextFreeByte + xWantedSize ) < configADJUSTED_HEAP_SIZE ) &&
                ( ( xNextFreeByte + xWantedSize ) > xNextFreeByte )	)/* 防止数值溢出 */
            {
   
                /* 返回首地址 */
                pvReturn = pucAlignedHeap + xNextFreeByte;
                /* 记录已分配空间大小 */
                xNextFreeByte += xWantedSize;
            }
        }
        /* 恢复任务 */
        ( void ) xTaskResumeAll();
    
        return pvReturn;
    }

需要注意的是,并未使用configTOTAL_HEAP_SIZE代表堆大小,而是用configADJUSTED_HEAP_SIZE表示堆大小,configADJUSTED_HEAP_SIZE定义如下

    #define configADJUSTED_HEAP_SIZE	( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT )

这里简单粗暴的丢弃掉了对齐字节数个字节,以此来表示堆的起始地址对齐的操作中损失的字节数(最多不会损失掉对齐字节数个字节)。个人认为这里可以改进一下,节省使用内存,既计算出对齐字节操作具体损失的字节数计入后续运算中(其实也节省不了多少内存)。

heap_2.c

与heap_1.c不同,heap_2.c允许使用vPortFree()函数来释放申请的内存,其算法原理是将空闲堆分为若干个大小不等的内存块,并将其按大小排序,使用单向链表连接起来,申请内存时,便从这些链表中寻找最小可满足申请需求的内存块进行分配。分配过程分为两步,首先将原先的内存块的链表项从链表中删除,其次是对当前内存块进行分割,将多余申请数的那部分内存变为新的链表项重新插入到链表中。释放过程则更为简单,只需要将释放的内存块重新插入到链表中即可。

首先分析heap_2.c是如何表示一个内存块并将内存块加入链表中的。内存块的链表项定义如下

    typedef struct A_BLOCK_LINK
    {
   
    	struct A_BLOCK_LINK *pxNextFreeBlock;	/* 指向下一个未被使用的内存块 */
    	size_t xBlockSize
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值