打印
[资源共享]

嵌入式C语言,如何正确使用动态内存?

[复制链接]
1543|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
cr315|  楼主 | 2023-3-2 16:07 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
常见错误与预防

1 分配后忘记释放内存
void func(void){    p = malloc(len);    do_something(p);    return;  /*错误!退出程序时没有释放内存*/}
    预防:编写代码时malloc()和free()保证成对出现,避免忘记资源回收。
int func(void){    p = malloc(len);    if (condition)        return -1;  /*错误!退出程序时没有释放内存*/    free(p);    return 0;}
    预防:一旦使用动态内存分配,请仔细检查程序的退出分支是否已经释放该动态内存。2 释放内存调用错误指针
void func(void){    p = malloc(len);    val = *p++;  /*错误!动态内存句柄不可移动*/    free(p);}
    预防:千万不要修改动态内存句柄!可以另外赋值给其他指针变量,再对该动态内存进行访问操作。3 分配内存不够导致溢出
void func(void){    len = strlen(str);    p = malloc(len);    strcpy(p, str);  /*错误!str的’\0’写到动态内存外*/}
    预防:分配内存前仔细思考长度是否足够,千万注意字符串拷贝占用内存比字符串长度大1。 自动查错机制    尽管在开发过程中坚守原则和谨慎编程甚至严格测试,然而内存泄露的错误还是难以杜绝,如何让系统自动查出内存泄露的错误呢?    一种比较好的方法是建立日志块,即每次分配内存时记录该内存块的指针和大小,释放时再去除该日志块,如果有内存泄露就会有对应的日志块记录这些内存没有释放,这样就可以提醒程序员进行查错。    有了上述日志块操作函数,再来实现动态内存分配与释放函数就很容易了。只有当处于DEBUG版本和打开内存调试DMEM_DBG时才进行日志登录,否则MallocExt()和FreeExt()函数与malloc()和free()是等价的,这样保证了系统处于发布版本时的性能。    代码已经过严格测试,但这不是盈利的商业代码,即没有版权。但如果因代码错误带来的任何损失作者具有免责权利。    代码部分:    首先定义日志块结构体:


/* Log of dynamic memory usage */typedef struct _dmem_log{    struct _dmem_log *p_stNext; /* Point to next log */    const void *p_vDMem; /* Point to allocated memory by this pointer */    INT32S iSize; /* Size of the allocated memory */} DMEM_LOG;

    然后为该结构体开辟内存:


static DMEM_LOG *s_pstFreeLog; /* Point to free log pool by this pointer */static INT8U s_byNumUsedLog;static DMEM_LOG *s_pstHeadLog; /* Point to used log chain by this pointer */
/* Pool of dynamic memory log */#define NUM_DMEM_LOG 20static DMEM_LOG s_astDMemLog[NUM_DMEM_LOG];

    下面是内存日志块的操作函数:初始化、插入日志和移除日志:


/**********************************************************                                                             *                    Initialize DMem Log* Description : Initialize log of dynamic memory* Arguments  : void* Returns      : void* Notes        :**********************************************************/static void InitDMemLog(void){    INT16S    nCnt;    /* Initialize pool of log */    for (nCnt = 0; nCnt < NUM_DMEM_LOG; ++nCnt)    {        /* Point to next one */        s_astDMemLog[nCnt].p_stNext = &s_astDMemLog[nCnt + 1];    }    s_astDMemLog[NUM_DMEM_LOG - 1].p_stNext = NULL;    s_pstFreeLog = &s_astDMemLog[0]; /* Point to the 1th log */    return;}
/**********************************************************                                                             *                       Log DMem* Description : Join an allocated memory into log pool* Arguments  : const void *p_vAddr    point to address of this allocated memory by this pointer*             INT32S iSize    size of this allocated memory* Returns      : void* Notes        :**********************************************************/static void LogDMem(const void *p_vAddr, INT32S iSize){    ASSERT(p_vAddr && iSize > 0);    DMEM_LOG *p_stLog;    #if OS_CRITICAL_METHOD == 3    OS_CPU_SR  cpu_sr;    #endif
    /* Get a log from free pool */    OS_ENTER_CRITICAL(); /* Avoid race condition on s_pstFreeLog */    if (!s_pstFreeLog)    {        OS_EXIT_CRITICAL();        PRINTF("Allocate DMemLog failed.\r\n");               return;    }    p_stLog = s_pstFreeLog;    s_pstFreeLog = s_pstFreeLog->p_stNext;    OS_EXIT_CRITICAL();
    /* Don't need to protect this log that is free one currently */    p_stLog->p_vDMem = p_vAddr;    p_stLog->iSize = iSize;
    /* Put this log into used chain */    OS_ENTER_CRITICAL(); /* Avoid race condition */    p_stLog->p_stNext = s_pstHeadLog;    s_pstHeadLog = p_stLog;    ++s_byNumUsedLog;    OS_EXIT_CRITICAL();
    return;}
/**********************************************************                                                             *                       Unlog DMem* Description : Remove an allocated memory from log pool* Arguments  : const void *p_vAddr point to address of this allocated memory by this pointer* Returns      : void* Notes        :**********************************************************/static void UnlogDMem(const void *p_vAddr){    ASSERT(p_vAddr);    DMEM_LOG    *p_stLog, *p_stPrev;    #if OS_CRITICAL_METHOD == 3    OS_CPU_SR  cpu_sr;    #endif
    /* Search the log */    OS_ENTER_CRITICAL(); /*Avoid race condition */    p_stLog = p_stPrev = s_pstHeadLog;    while (p_stLog)    {        if (p_vAddr == p_stLog->p_vDMem)        {         break; /* Have found */        }         
        p_stPrev = p_stLog;                p_stLog = p_stLog->p_stNext;    /* Move to next one */    }
    if (!p_stLog)    {        OS_EXIT_CRITICAL();        PRINTF("Search Log failed.\r\n");                 return;    }
    /* Remove from used pool */    if (p_stLog == s_pstHeadLog)    {     s_pstHeadLog = s_pstHeadLog->p_stNext;    }    else    {     p_stPrev->p_stNext = p_stLog->p_stNext;    }    --s_byNumUsedLog;    OS_EXIT_CRITICAL();
    /* Don't need to protect this log that is free one currently */    p_stLog->p_vDMem = NULL;    p_stLog->iSize = 0;
    /* Add into free pool */    OS_ENTER_CRITICAL(); /* Avoid race condition */    p_stLog->p_stNext = s_pstFreeLog;    s_pstFreeLog = p_stLog;    OS_EXIT_CRITICAL();
    return;}

    带日志记录功能的内存分配MallocExt()和内存释放FreeExt()函数:


/*********************************************************                                                    *                      Malloc Extension* Description : Malloc a block of memory and log it if need* Arguments : INT32S iSize    size of desired allocate memory* Returns: void *NULL= failed, otherwise=pointer of allocated memory* Notes        :**********************************************************/void *MallocExt(INT32S iSize){    ASSERT(iSize > 0);    void *p_vAddr;
    p_vAddr = malloc(iSize);    if (!p_vAddr)    {     PRINTF("malloc failed at %s line %d.\r\n", __FILE__, __LINE__);    }    else    {        #if (DMEM_DBG && DBG_VER)        memset(p_vAddr, 0xA3, iSize); /* Fill gargage for debug */        LogDMem(p_vAddr, iSize);    /* Log memory for debug */        #endif    }
    return p_vAddr;     }
/***********************************************************                      Free Extension* Description : Free a block of memory and unlog it if need* Arguments  : void * p_vMem point to the memory by this pointer* Returns      : void* Notes        :**********************************************************/void FreeExt(void *p_vMem){    ASSERT(p_vMem);
    free(p_vMem);      #if (DMEM_DBG && DBG_VER)    UnlogDMem

使用特权

评论回复
沙发
海滨消消| | 2023-4-25 16:28 | 只看该作者
闭坑宝典

使用特权

评论回复
板凳
海滨消消| | 2023-4-25 16:28 | 只看该作者
闭坑宝典

使用特权

评论回复
地板
豌豆爹| | 2023-9-28 09:57 | 只看该作者
尽可能地避免使用动态内存分配,优化数据结构,及时释放内存,避免使用全局变量和浮点数,以及使用内存池等技术来管理动态内存。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1196

主题

3012

帖子

0

粉丝