C语言之内存管理

        用C写程序的时候,管理内存是一件比较麻烦的事情,稍有不慎就容易导致内存泄露。因此,一种好的内存管理方式还是十分有必要的,尤其是代码量比较大的时候,更显其重要性。

       首先要管理内存,就得有一种有效的机制检测内存情况,该方面好像叫“打桩”,也不知道名字对不对。c语音内存的申请和释放主要使用malloc和free这两个函数。我们可以对malloc和free再次进行封装,比如我们将malloc封装为Malloc,对free封装为Free,在编程过程中使用Malloc和Free函数,而不使用原生的malloc和free函数。并创建一个全局结构变量,用于记录申请过和释放过的内存内存地址,然后进行对比,就能有效的检测到内存泄露点了。并通过printf将对应的内存泄露点位置打印出来,这样就能在每次运行后及时的检测内存情况,便于在编码过程中,及时的解决内存泄露问题。同时也能有效的监测是否存在重复释放等一系列情况,之前没有分享具体实现,今天分享出来,不然感觉写得文章很空。

    

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
#include "BDA_PortTable.h"


//=========================================================
//--------以下为内存泄漏检测
//=========================================================
#define TML_MAX	1024

static struct tagBDA_MEM_ITEM
{
	void * p;				//内存指针
	const char * name;		//内存分配点名字
	int line;				//行号
	long size;
}sg_memItems[TML_MAX] = {{0}};


/*
 * 初始化内存检测
 */
void BDA_MemCheckInit(void)
{
#if BDA_IS_MEMORY_CHECK == BDA_MEMORY_CHECK_OPEN
	BDA_memset(sg_memItems, 0, sizeof(sg_memItems));
#endif
}

/*
 * 退出内存检测
 */
void BDA_MemCheckExit(void)
{
#if BDA_IS_MEMORY_CHECK == BDA_MEMORY_CHECK_OPEN
	int i = 0;


	LOGW("\n###########################################################\n");
	LOGW("###########################################################\n");
	LOGW("检查内存泄漏情况\n");
	for ( i = 0; i < TML_MAX; i++ )
	{
		if (sg_memItems[i].p)
		{
			LOGW("###########################################################\n");
			LOGW("###########################################################\n");
			LOGW("未释放的内存 %s[%d] = 0x%08X\n", sg_memItems[i].name, sg_memItems[i].line, sg_memItems[i].p);
			LOGW("###########################################################\n");
		}
	}
#endif
}

//=========================================================
//--------以下为平台重载函数
//=========================================================
#if BDA_IS_MEMORY_CHECK == BDA_MEMORY_CHECK_CLOSE

void *BDA_malloc(int32_t size)
{
	return malloc(size);
}

#else

void *BDA_CheckMalloc(int32_t size, const char * name, int32_t line)
{
	int32_t i = 0;

	char *ptr = (char *)malloc(size);

	if ( ptr )
	{
		for ( i = 0; i < TML_MAX; i++ )
		{
			if (!sg_memItems[i].p)
			{
				sg_memItems[i].p = (void *)ptr;
				sg_memItems[i].name = name;
				sg_memItems[i].line = line;
				sg_memItems[i].size = size;

				break;
			}
		}

		if (i == TML_MAX)
		{
			LOGW("内存记录条目已经用满\n");
		}
	}

	return (void *)ptr;
}

#endif


#if BDA_IS_MEMORY_CHECK == BDA_MEMORY_CHECK_CLOSE

void BDA_free(void * p)
{
	free(p);
}

#else

void BDA_CheckFree(void * ptr, const char * name, int line)
{
	int32_t i = 0;

	for ( i = 0; i < TML_MAX; i++ )
	{
		if (((unsigned long)sg_memItems[i].p) == ((unsigned long)ptr))
		{
			sg_memItems[i].p = 0;
			sg_memItems[i].name = 0;
			sg_memItems[i].line = 0;
			sg_memItems[i].size = 0;

			break;
		}
	}

	if (i == TML_MAX)
	{
		LOGW("释放了未申请的内存 %s[%d] = 0x%08X\n", name, line, ptr);
	}

	free(ptr);
}

#endif

//这之下本来还封装了一些与操作系统相关的函数,由于与本文章没有什么关系,就不列举出来了,进行这样的封装,主要是为了跨平台移植的方便。
.... 

      从代码中,各位应该能看到,关于内存管理的,主要涉及到四个函数:
BDA_MemCheckInit(void);      //负责初始化内存管理结构
<pre name="code" class="cpp">void BDA_MemCheckExit(void); //负责在程序结束时,检测是否存在泄漏
<pre name="code" class="cpp">void *BDA_CheckMalloc(int32_t size, const char * name, int32_t line);  //对malloc进行封装,用于记录内存申请点
<pre name="code" class="cpp">void BDA_CheckFree(void * ptr, const char * name, int line);           //对free进行封装,用于释放内存并清除申请记录

 
 

      为了使这几个函数的使用方法与原生函数一直,在.h文件中做一下声明: 

void *BDA_CheckMalloc(int32_t size, const char * name, int32_t line);
void BDA_CheckFree(void * p, const char * name, int line);

#define BDA_malloc(x) BDA_CheckMalloc(x, __FILE__, __LINE__);
#define BDA_free(x) BDA_CheckFree(x, __FILE__, __LINE__);

     到此,大功告成,在实际项目开发时,采用一下结构:

void main()
{
	BDA_MemCheckInit();	//内存泄漏检测初始化

        //需要编写的代码

	BDA_MemCheckExit();	//内存泄漏检查退出
}
      采用这样的结构,就可以轻松的找到内存的泄漏点了。

      仅仅是能检测内存泄露情况是还不够的,良好的代码结构对于内存管理也是十分重要的。

     当我们面对较大的程序设计时,我们应当参考面向对象的编程思想,将一系列的数据结构抽象成一个个的类,每个类进行自己的内存管理,相对于类的客户端代码只需要在合适的时候销毁对应对象即可,这里可以参考一下c++构造函数和析构函数的思想,无需关心对象的内部内存如何释放。采用这样的方式,逐层封装,逐层的进行管理,每一层级的类调用下它之下的对象的销毁函数接口,从而实现更清晰的内存管理。

      如果代码进一步激增,估计还需要更完善的内存管理机制,目前还没有从事这样的项目开发,后期有机会,有经验了,再总结下来。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值