1. 程式人生 > >微控制器上記憶體管理(重定義malloc & free)de實現

微控制器上記憶體管理(重定義malloc & free)de實現

   在微控制器上經常會需要用到像標準c庫中的記憶體分配,可是微控制器並沒有記憶體管理機制,如果直接呼叫庫函式(malloc,free...),會導致記憶體碎片越用越多,很容易使系統崩潰掉,這裡分享一個自己寫的適用於微控制器的記憶體分配方法,具備輕量級的記憶體管理能力,有效減少記憶體碎片,提高微控制器系統工作穩定性。

   如下圖,heap_start開始的地方,是我們存放使用者資料的地方,在heap_end之前都是大小固定的一個個記憶體管理塊,記憶體管理塊用於記錄每次使用者申請記憶體的地址、大小、釋放情況。在malloc時,會優先選擇和使用者申請空間最相當的記憶體塊,以減少記憶體碎片產生。在free的記憶體塊時,如果遇到相鄰記憶體塊均為空閒塊時,便會將幾塊相鄰的記憶體塊合併成一塊,以減少記憶體碎片。

原始碼下載:

alloc.c

/*
********************************************************************************
*                                memory alloc 
*
*                            (c) Copyright 2018-2020;
*        All rights reserved.  Protected by international copyright laws.
*
*                                MEMORY ALLOC
*
* File    : mem_alloc.c
* By      : Recahrd.Zhang
* Version : V1.00
*
********************************************************************************
*/
#include <string.h>
#include "mem_alloc.h"
#include "debug.h"

#define MEM_ALLOC        1
#if defined (MEM_ALLOC)&&MEM_ALLOC
#define alloc_printf         printf
#else
#define alloc_printf(argv, ...)
#endif

#define MEM_SIZE         2*1024             /*記憶體池的大小 2 KBytes*/

static    char mem[MEM_SIZE];                   /*定義用來記憶體分配的陣列*/

#define MEM_START     &mem[0]                /*定義記憶體池的首地址*/
#define MEM_END       &mem[MEM_SIZE]        /*定義記憶體池的尾地址*/

enum USE_STA{                            /*定義記憶體塊的使用狀態(UNUSED 未使用),(USED 已使用)*/
    UNUSED = 0,
    USED   = 1
};

#pragma pack(1)
typedef struct mem_block{                /*定義記憶體管理塊的資料結構*/
    void             *mem_ptr;            /*當前記憶體塊的記憶體地址*/
    struct mem_block     *nxt_ptr;        /*下一個記憶體管理塊的地址*/
    unsigned int         mem_size;        /*當前記憶體塊的大小*/
    enum USE_STA        mem_sta;        /*當前記憶體塊的狀態*/
}mem_block;
#pragma pack()


#define BLK_SIZE    sizeof(mem_block)    /*記憶體管理塊的大小*/
#define HEAD_NODE    (MEM_END - BLK_SIZE)/*頭記憶體管理塊的地址*/

static signed char  mem_init_flag = -1; /*記憶體分配系統初始化的標誌(-1 未初始化),(1 已初始化)*/

/*
********************************************************************************
*                                   記憶體分配系統初始化                     
*
* 描述    : 初始化記憶體分配系統,為malloc和free做好準備工作。
*
* 引數  : 無
*
* 返回  : 無
********************************************************************************
*/
void mem_init(void)
{
    mem_block     *node;
    
    memset(mem,    0x00UL,    sizeof(mem));
    
    node = (mem_block     *)HEAD_NODE;
    node->mem_ptr         =     MEM_START;
    node->nxt_ptr         =     (mem_block *)HEAD_NODE;
    node->mem_size        =     MEM_SIZE - BLK_SIZE;
    node->mem_sta        =    UNUSED;
    
    mem_init_flag = 1;
}

/*
********************************************************************************
*                                   記憶體申請函式                     
*
* 描述    : 記憶體申請函式
*
* 引數  : nbytes    要申請的記憶體的位元組數。
*
* 返回  : 成功        返回申請到的記憶體的首地址
*          失敗        返回NULL
********************************************************************************
*/
static void *malloc(unsigned nbytes)
{
    unsigned int    suit_size = 0xFFFFFFFFUL;
    mem_block     *head_node=NULL, *tmp_node=NULL, *suit_node=NULL;

    if(nbytes == 0)
    {
        alloc_printf("引數非法!\r\n");
        return NULL;
    }
    if(mem_init_flag < 0)
    {
        alloc_printf("未初始化,先初始化.\r\n");
        mem_init();
    }
    
    head_node = tmp_node = (mem_block *)HEAD_NODE;
    while(1)
    {
        if(tmp_node->mem_sta == UNUSED)
        {
            if(nbytes <= tmp_node->mem_size && tmp_node->mem_size < suit_size)
            {
                suit_node = tmp_node;
                suit_size = suit_node->mem_size;
            }
        }
        tmp_node = tmp_node->nxt_ptr;
        if(tmp_node == head_node)
        {
            if(suit_node == NULL)
            {
                alloc_printf("NULL\r\n");
                return NULL;
            }
            break;
        }
    }

    if(nbytes <= suit_node->mem_size && (nbytes + BLK_SIZE) >= suit_node->mem_size)
    {
        suit_node->mem_sta = USED;
        return suit_node->mem_ptr;
    }
    else    if(suit_node->mem_size > (nbytes + BLK_SIZE))
    {
        tmp_node = suit_node->mem_ptr; 
        tmp_node = (mem_block *)((unsigned char *)tmp_node + nbytes);
        tmp_node->mem_ptr  = suit_node->mem_ptr;
        tmp_node->nxt_ptr  = suit_node->nxt_ptr;
        tmp_node->mem_size = nbytes;
        tmp_node->mem_sta  = USED;
        
        suit_node->mem_ptr      = (mem_block *)((unsigned char *)tmp_node + BLK_SIZE);
        suit_node->nxt_ptr   =  tmp_node;
        suit_node->mem_size -= (nbytes + BLK_SIZE);
        suit_node->mem_sta   = UNUSED;
        
        return tmp_node->mem_ptr;
    }
    else
    {
        alloc_printf("%s,size err!\r\n",__FUNCTION__);
    }
    
    return NULL;
}

/*
********************************************************************************
*                                   記憶體釋放函式                     
*
* 描述    : 記憶體釋放函式 
*
* 引數  : ap        要釋放的記憶體塊的指標。
*
* 返回  : 無
********************************************************************************
*/
static void free(void *ap)
{
    mem_block     *head_node, *tmp_node, *nxt_node;
    
    if(ap == NULL)
        return;
    if(mem_init_flag < 0)
    {
        return;
    }
    head_node = tmp_node = (mem_block *)HEAD_NODE;
    while(1)
    {
        if(tmp_node->mem_ptr == ap)
        {
            if(tmp_node->mem_sta != UNUSED)
            {
                tmp_node->mem_sta = UNUSED;
                break;
            }
            else
            {
                alloc_printf("ap:0x%08x 已經釋放,無需再次釋放\r\n",ap);
                return;
            }
        }
        
        tmp_node = tmp_node->nxt_ptr;
        if(tmp_node == head_node)
        {
            alloc_printf("%s,can not found ap!\r\n",__FUNCTION__);
            return ;
        }
    }

AGAIN:    
    head_node = tmp_node = (mem_block *)HEAD_NODE;
    while(1)
    {
        nxt_node = tmp_node->nxt_ptr;
        if(nxt_node == head_node)
        {
            break;
        }
        if(tmp_node->mem_sta == UNUSED && nxt_node->mem_sta == UNUSED)
        {
            tmp_node->mem_ptr     = nxt_node->mem_ptr;
            tmp_node->nxt_ptr     = nxt_node->nxt_ptr;
            tmp_node->mem_size += nxt_node->mem_size + BLK_SIZE;
            tmp_node->mem_sta    =  UNUSED;
            
            goto AGAIN;
        }
        tmp_node = nxt_node;
    }
}

void *m_malloc(unsigned nbytes)
{
    return malloc(nbytes);
}

void m_free(void *ap)
{
    free(ap);
}

alloc.h
 

#ifndef __MEM_ALLOC_H__
#define __MEM_ALLOC_H__

void *m_malloc(unsigned nbytes);
void  m_free(void *ap);

#endif

test.c:

#include <stdio.h>
#include "alloc.h"

#define alloc_printf  pritnf

/*
********************************************************************************
*                                   記憶體列印函式                     
*
* 描述    : 列印記憶體系統中每一個記憶體塊的資訊
*
* 引數  : 無
*
* 返回  : 無
********************************************************************************
*/
void mem_print(void)
{
    unsigned int i = 0;
    mem_block     *head_node, *tmp_node;

    if(mem_init_flag < 0)
    {
        alloc_printf("未初始化,先初始化.\r\n");
        mem_init();
    }
    head_node = tmp_node = (mem_block *)HEAD_NODE;
    alloc_printf("\r\n#############################\r\n");
    while(1)
    {
        alloc_printf("\r\nNO.%d:\r\n",i++);
        alloc_printf("blk_ptr:0x%08x\r\n",tmp_node);
        alloc_printf("mem_ptr:0x%08x\r\n",tmp_node->mem_ptr);
        alloc_printf("nxt_ptr:0x%08x\r\n",tmp_node->nxt_ptr);
        alloc_printf("mem_size:%d\r\n",tmp_node->mem_size);
        alloc_printf("mem_sta:%d\r\n",tmp_node->mem_sta);

        tmp_node = tmp_node->nxt_ptr;
        if(tmp_node == head_node)
        {
            break;
        }
    }
    alloc_printf("\r\n#############################\r\n");
}

void buff_print(unsigned char *buf,unsigned int len)
{
    unsigned int i;

    alloc_printf("\r\n");
    for(i=0;i<len;i++)
    {
        if(i%16 == 0 && i != 0)
        {
            alloc_printf("\r\n");
        }
        alloc_printf("0x%02x,",buf[i]);
        //alloc_printf("%c",buf[i]);
    }
    alloc_printf("\r\n");
}

void *m_malloc(unsigned nbytes)
{
    return malloc(nbytes);
}

void m_free(void *ap)
{
    free(ap);
}

typedef char (*array)[4];
/*
********************************************************************************
*                                   記憶體分配函式測試                     
*
* 描述    : 測試記憶體分配系統中每一個函式的功能
*
* 引數  : 無
*
* 返回  : 無
********************************************************************************
*/
void alloc_test(void)
{  
    array ptr = NULL;
    unsigned int i,j;

    alloc_printf("Ptr1:%d\r\n",sizeof(ptr));
    ptr = m_malloc(16);
    if(ptr == NULL)
    {
        alloc_printf("malloc failed.\r\n");
        return;
    }
    mem_print();
    
    for(i=0;i<4;i++)
    {
        for(j=0;j<4;j++)
        {
            ptr[i][j] = i;
        }
    }
    m_free(ptr);
    mem_print();
    buff_print((unsigned char *)ptr, 16);
}