首页 > 其他 > 详细

正确使用动态内存

时间:2014-05-25 10:58:59      阅读:512      评论:0      收藏:0      [点我收藏+]

正确使用动态内存

一.   常见错误与预防

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 20

static 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(p_vMem);    /* Remove memory from log */

#endif

 return;

}

正确使用动态内存,布布扣,bubuko.com

正确使用动态内存

原文:http://blog.csdn.net/jiangjunjie_2005/article/details/26937879

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!