C语言--操作内存的工具

C语言–操作内存的工具

C语言本身作为一个操作内存的工具,在数据使用方面都需要直接申请、释放内存,在编码过程中往往不可避免出现一些内存使用的错误。下面一些常用的编码技巧,能帮组尽量减速或排查错误。

一、内存分配

static addr_record cr[256] = {0};
static addr_record fr[256] = {0};

// 4      2      2       4                   4
// ptr + size + free + red_zone + data +  red_zone
void* app_malloc(long size) 
{
	void *data = NULL;

	if (size <= 0) {
		APP_ERROR("size %l error", size);
		return data;
	}
	
	char *ptr = (char *)malloc(size + 4 + 2 + 2 + 4 + 4);
	if (NULL == ptr) {
		APP_ERROR("malloc size %l failed", size);
		return data;
	}

	data = ptr + 12;
	long address = (long)data;
	*((long *) ptr) = address;
	*((short*) (ptr+4)) = size;
	*((short*) (ptr+6)) = 0; 
	*((long*) (ptr+8)) = 0x6e6e6e6e; 

	*((long*) ((char*)data + size)) = 0x6e6e6e6e;
    
    memset(data, 0x0, size);
    
	if (size < 256) {
		cr[size].addr = address;
		cr[size].size = size;
		cr[size].num ++;
	}

	return data;
}

申请一块内存,在内存前后添加上自拟的字段(也可以理解成协议),例子中最前4个字节是申请内存的首地址,再后2个字节是申请内存大小,再后2字节填0,再后4字节填自定义数,方便查找,申请内存的最后也附上自定义数(自定义数的作用可以方便查找内存开始的地方,也方便做内存间隔断的标识)。

void app_free(void *data) {
	if (NULL == data) {
		return;
	}

	char *ptr = (char*) data  - 12;

	if (*((long*) (ptr+8)) != 0x6e6e6e6e) {
		APP_ERROR("Memory out of bounds");
	}

	short size = *((short*) (ptr+4));

	if (size < 0) {
		APP_WARN("some one do not use app malloc ?");
	} else {

		if (size < 256) {
			fr[size].size = size;
			fr[size].num ++;
		}

	}
	free(ptr);

	return;
}

释放内存时也需要向前移动地址,把之前自定义部分包含进去,若报错则可能出现内存问题。

typedef struct {
	long addr;
	int size;
	int num;
} addr_record;

结构体主要用来计数,计算malloc和free次数,方便查内存溢出等问题;

例子

现象:Segmentation fault.

排查过程:gdb运行模式下排查:首先bt查看代码错误位置

在这里插入图片描述

确定代码错误发生在app_trigger函数,f 0进入栈查看frame是否正常

在这里插入图片描述

确认frame正常则查看entry地址(app_trigger函数参数)

在这里插入图片描述

发现entry是个错误地址,再看g_app_ptr缓存中的4个链表指针,发现第二、第三链表的指针地址都存在问题;打印g_app_ptr缓存的内容

在这里插入图片描述

根据红框中的数值发现内存并未被越界操作,所以确定是代码本身操作g_app_ptr缓存不当。其中红框中的值是分配g_app_ptr时在其周围设置的防越界标志。

再看代码逻辑,发现app_trigger 调用时可能出现g_app_ptr缓存未初始化或者entry还未注册添加到g_app_ptr缓存中,所以确认是此处可能造成调用顺序不当导致内存错误。

二、内存连续性

内存malloc次数过多会导致内存块连续性降低,内存数据查找速率下降;在结构体内部存在指针,为了避免内存不连续,在给结构体内分配内存时,同时给结构体内部的指针分配对应大小的内存。

typedef struct my_type_s {
	struct list_head list;
	int   repeate;
	int up_period;/*更新时间*/

	int priority; /*优先级*/

	char *info;  /*背景详细信息,复杂引导信息*/
	
} my_type_t;

以上结构体包含一个char指针,一般在使用该结构体的时候先malloc(sizeof(my_type_t))内存,然后再进行my_type_t->info的内存分配并初始化;但建议在分配my_type_t结构体内存的同时分配info的内存,编码如下:

my_type_t* my_malloc(int priv_size) {
	my_type_t *my_type = NULL;

	my_type = (my_type_t *)app_malloc(sizeof (my_type_t) + priv_size);
	if (NULL == my_type) {
		ERROR("malloc event failed");
		return my_type;
	}
	
	my_type->info = (char *)my_type + sizeof (my_type_t);
	return event;
}
void event_free(my_type_t *my_type) {
	app_free(my_type);

	return;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值