OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4037|回复: 3

动态内存管理 升级实例分享

[复制链接]

3

主题

12

帖子

0

精华

初级会员

Rank: 2

积分
54
金钱
54
注册时间
2019-5-27
在线时间
17 小时
发表于 2021-8-19 10:19:12 | 显示全部楼层 |阅读模式
最近读了FreeRTOS内存管理的源码,特将原子哥的例程《内存管理试验》的源码,运用FreeRTOS内存管理的思想进行改造
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

3

主题

12

帖子

0

精华

初级会员

Rank: 2

积分
54
金钱
54
注册时间
2019-5-27
在线时间
17 小时
 楼主| 发表于 2021-8-19 10:21:23 | 显示全部楼层
源码如下:
#include <stdlib.h>

/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
all the API functions to use the MPU wrappers.  That should only be done when
task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE

#include "my_malloc.h"

#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE

/* Block sizes must not get too small. */
#define heapMINIMUM_BLOCK_SIZE        ( ( size_t ) ( xHeapStructSize << 1 ) )

/* Assumes 8bit bytes! */
#define heapBITS_PER_BYTE                ( ( size_t ) 8 )

#define BYTE_ALIGNMENT 8                                                                                                                                       
#define BYTE_ALIGNMENT_MASK (0X0007)
#define COVERAGE_TEST_MAKER()

//内存池(64字节对齐)
static u8 mem1base[MEM1_MAX_SIZE] __attribute__((aligned (64)));                                        //内部SRAM内存池
static u8 mem2base[MEM2_MAX_SIZE] __attribute__((aligned (64), section(".ARM.__at_0XC0600000")));                                        //外部SDRAM内存池,前面2M给LTDC用了(1024*1000*2),2M给了屏幕COLOR_BUF_SIZE
static u8 mem3base[MEM3_MAX_SIZE] __attribute__((aligned (64), section(".ARM.__at_0X20000000")));                                        //内部DTCM内存池

/*
//内存池(64字节对齐)
__align(64) u8 mem1base[MEM1_MAX_SIZE];                                                                                                        //内部SRAM内存池
__align(64) u8 mem2base[MEM2_MAX_SIZE] __attribute__((at(0XC01F4000)));                                        //外部SDRAM内存池,前面2M给LTDC用了(1024*1000*2)
__align(64) u8 mem3base[MEM3_MAX_SIZE] __attribute__((at(0X20000000)));                                        //内部DTCM内存池
*/

/* Define the linked list structure.  This is used to link free blocks in order
of their memory address. */
typedef struct A_BLOCK_LINK
{
        struct A_BLOCK_LINK *pxNextFreeBlock;        /*<< The next free block in the list. */
        size_t xBlockSize;                                                /*<< The size of the free block. */
} BlockLink_t;

/*-----------------------------------------------------------*/

/*
* Inserts a block of memory that is being freed into the correct position in
* the list of free memory blocks.  The block being freed will be merged with
* the block in front it and/or the block behind it if the memory blocks are
* adjacent to each other.
*/
static void prvInsertBlockIntoFreeList(MemType_t memx, BlockLink_t *pxBlockToInsert);

/*
* Called automatically to setup the required heap structures the first time
* pvPortMalloc() is called.
*/
static void prvHeapInit(MemType_t memx);

/*-----------------------------------------------------------*/

static const size_t xHeapStructSize        = ( sizeof( BlockLink_t ) + ( ( size_t ) ( BYTE_ALIGNMENT - 1 ) ) ) & ~( ( size_t ) BYTE_ALIGNMENT_MASK );

typedef struct _MallocManager
{
        u8 * ucHeap;                        //起始地址
        u32 heapSize;                        //堆大小
        u32 * pStartAddress;
        BlockLink_t xStart;
        BlockLink_t * pxEnd;
        size_t xFreeBytesRemaining;                                //内存堆剩余大小
        size_t xMinimumEverFreeBytesRemaining;        //最小空闲内存块大小
}MallocManager;

MallocManager mallocManager[SRAMBANK];

/* Gets set to the top bit of an size_t type.  When this bit in the xBlockSize
member of an BlockLink_t structure is set then the block belongs to the
application.  When the bit is free the block is still part of the free heap
space. */
static size_t xBlockAllocatedBit = 0;




//初始化内存
//memx: 内存堆名称
static void prvHeapInit(MemType_t memx)
{
        //根据堆类型来确定不同的堆大小,以及起始地址
        if(memx == MEM_SRAM)
        {
                mallocManager[memx].heapSize = MEM1_MAX_SIZE;
                mallocManager[memx].ucHeap = mem1base;
        }
        else if(memx == MEM_DRAM)
        {
                mallocManager[memx].heapSize = MEM2_MAX_SIZE;
                mallocManager[memx].ucHeap = mem2base;
        }
        else
        {
                mallocManager[memx].heapSize = MEM3_MAX_SIZE;
                mallocManager[memx].ucHeap = mem3base;
        }
       
        BlockLink_t *pxFirstFreeBlock;
        uint8_t *pucAlignedHeap;
        size_t uxAddress;
        size_t xTotalHeapSize = mallocManager[memx].heapSize;

        //保证字节对齐
        uxAddress = (size_t)mallocManager[memx].ucHeap;
        if((uxAddress & BYTE_ALIGNMENT_MASK) != 0)
        {
                uxAddress += (BYTE_ALIGNMENT - 1);
                uxAddress &= ~((size_t)BYTE_ALIGNMENT_MASK);
                xTotalHeapSize = uxAddress - (size_t)mallocManager[memx].ucHeap;
        }
        pucAlignedHeap = (uint8_t  *)uxAddress;
       
        //xStart为可用内存块链表头
        mallocManager[memx].xStart.pxNextFreeBlock = (void *)pucAlignedHeap;
        mallocManager[memx].xStart.xBlockSize = (size_t) 0;
       
        //pxEnd为可用内存块链表尾,放在内存堆尾部
        uxAddress = ( ( size_t ) pucAlignedHeap ) + xTotalHeapSize;
        uxAddress -= xHeapStructSize;
        uxAddress &= ~( ( size_t ) BYTE_ALIGNMENT_MASK );
        mallocManager[memx].pxEnd = ( void * ) uxAddress;
        mallocManager[memx].pxEnd->xBlockSize = 0;
        mallocManager[memx].pxEnd->pxNextFreeBlock = NULL;
       
        //初始化之后,系统只有一个空闲的内存块
        pxFirstFreeBlock = ( void * ) pucAlignedHeap;
        pxFirstFreeBlock->xBlockSize = uxAddress - ( size_t ) pxFirstFreeBlock;
        pxFirstFreeBlock->pxNextFreeBlock = mallocManager[memx].pxEnd;
       
        /* Only one block exists - and it covers the entire usable heap space. */
        mallocManager[memx].xMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
        mallocManager[memx].xFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
       
        /* Work out the position of the top bit in a size_t variable. */
        xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 );
}


//将某个内存块插入到空闲内存链表中
//memx: 内存堆类型
//pxBlockToInsert:指向内存块的指针
static void prvInsertBlockIntoFreeList(MemType_t memx, BlockLink_t *pxBlockToInsert)
{
        BlockLink_t *pxIterator;
        uint8_t *puc;
       
        //遍历链表,直到找到可以插入的地方
        for( pxIterator = &mallocManager[memx].xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock )
        {
                /* Nothing to do here, just iterate to the right position. */
        }
       
        //判断是否可以和前面的内存合并
        puc = (uint8_t *)pxIterator;
        if((puc + pxIterator->xBlockSize) == (uint8_t *)pxBlockToInsert)
        {
                //合并成一个
                pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;
                pxBlockToInsert = pxIterator;
        }
        else
        {
                COVERAGE_TEST_MAKER();
        }
       
        //判断是否可以和后面的内存块合并
        puc = (uint8_t *)pxBlockToInsert;
        if((puc + pxBlockToInsert->xBlockSize) == (uint8_t *)pxIterator->pxNextFreeBlock)
        {
                if(pxIterator->pxNextFreeBlock != mallocManager[memx].pxEnd)
                {
                        //两个内存块合并成一个大的内存块
                        pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize;
                        pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock;
                }
                else
                {
                        pxBlockToInsert->pxNextFreeBlock = mallocManager[memx].pxEnd;
                }
        }
        else
        {
                pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;
        }
       
        //没有任何内存合并,正常插入
        if(pxIterator != pxBlockToInsert)
        {
                pxIterator->pxNextFreeBlock = pxBlockToInsert;
        }
        else
        {
                COVERAGE_TEST_MAKER();
        }
}

//分配内存
//memx: 内存堆类型
//xWantedSize: 所需要的大小
//返回:指向所分配内存的指针
void *myMalloc(MemType_t memx, u32 xWantedSize)
{
        BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink;
        void *pvReturn = NULL;
       
        //如果是首次调用,则需要初始化
        if(mallocManager[memx].pxEnd == NULL)
        {
                prvHeapInit(memx);
        }
        else
        {
                COVERAGE_TEST_MAKER();
        }
        /* Check the requested block size 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((xWantedSize & xBlockAllocatedBit) == 0)
        {
                //实际申请内存大小需要加上头部字节
                if(xWantedSize > 0)
                {
                        xWantedSize += xHeapStructSize; //加上头部(8字节)
                        //字节对齐
                        if( ( xWantedSize & BYTE_ALIGNMENT_MASK ) != 0x00 )
                        {
                                /* Byte alignment required. */
                                xWantedSize += ( BYTE_ALIGNMENT - ( xWantedSize & BYTE_ALIGNMENT_MASK ) );
                                MY_ASSERT( ( xWantedSize & BYTE_ALIGNMENT_MASK ) == 0 );
                        }
                        else
                        {
                                COVERAGE_TEST_MAKER();
                        }
                }
                else
                {
                        COVERAGE_TEST_MAKER();
                }
                if((xWantedSize > 0) && (xWantedSize <= mallocManager[memx].xFreeBytesRemaining))
                {
                        //从起始地址开始查找链表,直到找到size满足需要的block
                        pxPreviousBlock = &mallocManager[memx].xStart;
                        pxBlock = mallocManager[memx].xStart.pxNextFreeBlock;
                        while((pxBlock->xBlockSize < xWantedSize) && (pxBlock->pxNextFreeBlock != NULL))
                        {
                                pxPreviousBlock = pxBlock;
                                pxBlock = pxBlock->pxNextFreeBlock;
                        }
                        if(pxBlock != mallocManager[memx].pxEnd)
                        {
                                //返回指向当前内存块的指针(需要跳过头部)
                                pvReturn = (void *)(((uint8_t *)pxPreviousBlock->pxNextFreeBlock) + xHeapStructSize);
                               
                                //从链表剔除所分配的内存块
                                pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;
                       
                                //如果当前块内存大于所需要的,则将其进行拆分
                                if((pxBlock->xBlockSize - xWantedSize) > heapMINIMUM_BLOCK_SIZE)
                                {
                                        //将拆分出来的内存块作为链表插入到内存堆链表中
                                        pxNewBlockLink = (void *)(((uint8_t *)pxBlock) + xWantedSize);
                                        MY_ASSERT((((size_t)pxNewBlockLink) & BYTE_ALIGNMENT_MASK) == 0);
                               
                                        //重新计算当前内存块尺寸,以便其满足需求
                                        pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
                                        pxBlock->xBlockSize = xWantedSize;
                               
                                        //将其插入空闲链表中
                                        prvInsertBlockIntoFreeList(memx, pxNewBlockLink);
                                }
                                else
                                {
                                        COVERAGE_TEST_MAKER();
                                }
                       
                                mallocManager[memx].xFreeBytesRemaining -= pxBlock->xBlockSize;
                       
                                if(mallocManager[memx].xFreeBytesRemaining < mallocManager[memx].xMinimumEverFreeBytesRemaining)
                                {
                                        mallocManager[memx].xMinimumEverFreeBytesRemaining = mallocManager[memx].xFreeBytesRemaining;
                                }
                                else
                                {
                                        COVERAGE_TEST_MAKER();
                                }
                       
                                pxBlock->xBlockSize |= xBlockAllocatedBit;
                                pxBlock->pxNextFreeBlock = NULL;               
                        }
                        else
                        {
                                COVERAGE_TEST_MAKER();
                        }
                }
                else
                {
                        COVERAGE_TEST_MAKER();
                }
        }
        else
        {
                COVERAGE_TEST_MAKER();
        }
       
        MY_ASSERT((((size_t)pvReturn) & (size_t)BYTE_ALIGNMENT_MASK) == 0);
        return pvReturn;
}       

//释放内存
//memx: 内存类型
//pAddr: 指向内存的指针
void myFree(MemType_t memx, void *pAddr)
{
        uint8_t *puc = (uint8_t *)pAddr;
        BlockLink_t *pxLink;
       
        if(pAddr != NULL)
        {
                puc -= xHeapStructSize;        //减去头部,才是该内存块的实际地址
                pxLink = (void *)puc;        //防止编译器报错
               
                //检查该内存块是否已经被分配过
                MY_ASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 );
                MY_ASSERT( pxLink->pxNextFreeBlock == NULL );
               
                if((pxLink->xBlockSize & xBlockAllocatedBit) != 0)
                {
                        if(pxLink->pxNextFreeBlock == NULL)
                        {
                                //最高位置0,表示该块已经处于未分配状态
                                pxLink->xBlockSize &= ~xBlockAllocatedBit;
                               
                                //将该内存块加入到内存块链表中
                                mallocManager[memx].xFreeBytesRemaining += pxLink->xBlockSize;
                                prvInsertBlockIntoFreeList(memx, ((BlockLink_t *)pxLink));
                        }
                        else
                        {
                                COVERAGE_TEST_MAKER();
                        }
                }
                else
                {
                        COVERAGE_TEST_MAKER();
                }
        }
}

//返回内存堆剩余大小
//memx: 内存堆类型
//返回: 剩余大小
u32 getFreeHeapSize(MemType_t memx)
{
        return mallocManager[memx].xFreeBytesRemaining;
}

//返回最下空闲内存块大小
//memx: 内存堆类型
//返回: 剩余大小
u32 getMinimumEverFreeHeapSize(MemType_t memx)
{
        return mallocManager[memx].xMinimumEverFreeBytesRemaining;
}


回复 支持 反对

使用道具 举报

3

主题

12

帖子

0

精华

初级会员

Rank: 2

积分
54
金钱
54
注册时间
2019-5-27
在线时间
17 小时
 楼主| 发表于 2021-8-19 10:24:06 | 显示全部楼层
这段源码借鉴了 FreeRTOS的heap_4的内存分配源码,有兴趣的同学可以读一下源码
回复 支持 反对

使用道具 举报

2

主题

592

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1458
金钱
1458
注册时间
2019-7-28
在线时间
137 小时
发表于 2021-8-19 18:14:05 | 显示全部楼层
感谢楼主分享   
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-2-27 02:46

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表