FreeRTOS内存申请函数pvPortMalloc源码分析(10.5.1版本)

void * pvPortMalloc( size_t xWantedSize )
{
    BlockLink_t * pxBlock;
    BlockLink_t * pxPreviousBlock;
    BlockLink_t * pxNewBlockLink;
    void * pvReturn = NULL;
    size_t xAdditionalRequiredSize;

    vTaskSuspendAll();
    {
        /* If this is the first call to malloc then the heap will require
         * initialisation to setup the list of free blocks. */
        if( pxEnd == NULL )
        {
            prvHeapInit();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }

        if( xWantedSize > 0 )
        {
            /* The wanted size must be increased so it can contain a BlockLink_t
             * structure in addition to the requested amount of bytes. Some
             * additional increment may also be needed for alignment. */
            /* 需要增加的内存空间 */
            xAdditionalRequiredSize = xHeapStructSize + portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK );

            if( heapADD_WILL_OVERFLOW( xWantedSize, xAdditionalRequiredSize ) == 0 )
            {
                xWantedSize += xAdditionalRequiredSize;
            }
            else
            {
                xWantedSize = 0;
            }
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }

        /* Check the block size we are trying to allocate is not so large that the
         * top bit is set.  The top bit of the block size member of the BlockLink_t
         * structure is used to determine who owns the block - the application or
         * the kernel, so it must be free. */
        if( heapBLOCK_SIZE_IS_VALID( xWantedSize ) != 0 )
        {
            /* 内存大小溢出检查 */
            if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )
            {
                /* Traverse the list from the start (lowest address) block until
                 * one of adequate size is found. */
                pxPreviousBlock = &xStart;
                pxBlock = xStart.pxNextFreeBlock;

                /* 有足够大的空闲内存块,且没有到末尾,跳出循环 */
                while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )
                {
                    pxPreviousBlock = pxBlock;
                    pxBlock = pxBlock->pxNextFreeBlock;
                }

                /* If the end marker was reached then a block of adequate size
                 * was not found. */
                /* pxBlock 可用 */
                if( pxBlock != pxEnd )
                {
                    /* Return the memory space pointed to - jumping over the
                     * BlockLink_t structure at its start. */
                    /* 返回可用内存的起始地址,要跳过 xHeapStructSize 大小的结构体 */
                    pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + xHeapStructSize );

                    /* This block is being returned for use so must be taken out
                     * of the list of free blocks. */
                    /* 更新空闲链表的指向,将使用的内存块移除列表 */
                    pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;

                    /* If the block is larger than required it can be split into
                     * two. */
                    /* 要使用的内存块大于申请的空间,将剩余块插回空闲列表 */
                    if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
                    {
                        /* This block is to be split into two.  Create a new
                         * block following the number of bytes requested. The void
                         * cast is used to prevent byte alignment warnings from the
                         * compiler. */
                        /* 剩余地址的起始地址 */
                        pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );
                        configASSERT( ( ( ( size_t ) pxNewBlockLink ) & portBYTE_ALIGNMENT_MASK ) == 0 );

                        /* Calculate the sizes of two blocks split from the
                         * single block. */
                        /* 计算剩余块的大小 */
                        pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
                        
                        /* 赋值要使用的块大小 */
                        pxBlock->xBlockSize = xWantedSize;

                        /* Insert the new block into the list of free blocks. */
                        /* 将剩余块插回空闲列表 */
                        prvInsertBlockIntoFreeList( pxNewBlockLink );
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }

                    /* 更新剩余空闲内存大小 */
                    xFreeBytesRemaining -= pxBlock->xBlockSize;

                    /* 更新历史最小剩余 */
                    if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )
                    {
                        xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }

                    /* The block is being returned - it is allocated and owned
                     * by the application and has no "next" block. */
                    /* 标记内存块被使用 */
                    heapALLOCATE_BLOCK( pxBlock );

                    /* 内存块被使用,将空闲列表指针清空 */
                    pxBlock->pxNextFreeBlock = NULL;

                    /* 更新成功申请次数 */
                    xNumberOfSuccessfulAllocations++;
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }

        traceMALLOC( pvReturn, xWantedSize );
    }
    ( void ) xTaskResumeAll();

    #if ( configUSE_MALLOC_FAILED_HOOK == 1 )
    {
        if( pvReturn == NULL )
        {
            vApplicationMallocFailedHook();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    #endif /* if ( configUSE_MALLOC_FAILED_HOOK == 1 ) */

    configASSERT( ( ( ( size_t ) pvReturn ) & ( size_t ) portBYTE_ALIGNMENT_MASK ) == 0 );
    return pvReturn;
}

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
FreeRTOS内存申请和释放是通过内置的动态内存管理函数来实现的。FreeRTOS 提供了两种内存管理方案:heap_1 和 heap_5。 heap_1 方案是最简单的内存管理方案,它只需要一个静态数组来存储内存。这个数组的大小是在编译时确定的,因此无法动态调整。heap_5 方案则需要使用操作系统提供的动态内存分配函数,例如 malloc() 和 free()。 在使用 FreeRTOS 动态内存管理函数时,需要注意以下几点: 1. 必须在任务创建之前初始化内存管理函数。 2. 内存申请和释放必须在同一任务中进行。 3. 如果使用 heap_1 方案,需要在内存申请前禁用任务调度。 4. 如果使用 heap_5 方案,需要配置操作系统内存管理函数。 下面是 heap_1 方案内存申请和释放的示例代码: ``` /* 定义用于内存管理的静态数组 */ #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 10 * 1024 ) ) static uint8_t ucHeap[configTOTAL_HEAP_SIZE]; /* 初始化内存管理函数 */ void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions ) { /* 将静态数组作为内存区域注册 */ xHeapRegions = pxHeapRegions; xHeapRegions[0].pucStartAddress = ucHeap; xHeapRegions[0].xSizeInBytes = configTOTAL_HEAP_SIZE; } /* 内存申请 */ void *pvPortMalloc( size_t xWantedSize ) { void *pvReturn; /* 禁用任务调度 */ vTaskSuspendAll(); /* 调用内存管理函数进行内存申请 */ pvReturn = prvHeapMalloc( xWantedSize ); /* 恢复任务调度 */ xTaskResumeAll(); return pvReturn; } /* 内存释放 */ void vPortFree( void *pv ) { /* 禁用任务调度 */ vTaskSuspendAll(); /* 调用内存管理函数进行内存释放 */ vHeapFree( pv ); /* 恢复任务调度 */ xTaskResumeAll(); } ``` 注意,在使用 heap_1 方案时,需要调用 vPortDefineHeapRegions() 函数注册内存区域。在内存申请前需要禁用任务调度,以避免多个任务同时申请内存导致冲突。在内存释放后需要恢复任务调度。 使用 heap_5 方案时,需要在 FreeRTOS 中配置操作系统内存管理函数。配置方法可以参考官方文档:https://www.freertos.org/a00111.html。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

plmm烟酒僧

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值