首页天道酬勤c语言malloc函数头文件,c语言中malloc函数的头文件

c语言malloc函数头文件,c语言中malloc函数的头文件

张世龙 05-12 22:40 127次浏览

(evn : gcc版本5.4.020160609 (Ubuntu5.4.0-6Ubuntu 1至16.04.10 ) ) ) ) ) ) ) ) )

摘要:

方法概述

如何检测项目中的内存泄漏(带代码) ) )。

如何确定项目中的内存泄漏(带代码)

心得和建议

1 .方法介绍

该方法的原理很简单,通常从程序启动到成功结束malloc和free调用的次数必须相同,如果malloc的调用次数free的调用次数相同

项目中发生内存泄漏。 基于上述原理,我们可以自己封装一组malloc和free,用dydyx做手脚。 当然,过程中有需要注意的地方。 详情请参阅以下内容~

2 .如何检测项目中的内存泄漏

如果只是检查项目是否存在内存泄漏,则可以定义一个计数器count,将其放入重新封装的test_malloc、test_free函数中。 调用test_malloc时,调用count,free时,调用count--。 程序执行结束时,如果count大于0,则表示存在内存泄漏; 如果count为0,则没有内存泄漏。 如果计数小于零,该死。 哈哈,代码如下。 附上详细评论:

#包含

#包含

#包含

#包含

#包含

#包含

静态pthread _ mutex _ t lock; /*锁定count*/

静态输入计数=0; /*计数器、malloc: count和free: count--*/

void*test_malloc(size_tsize ) )。

{

void * new_mem;

资产(size!=0;

new_mem=malloc(size;

if(new_mem )是

{/*注意如果malloc成功,则返回count*/

pthread_mutex_lock(lock;

出局;

Phread_mutex_unlock(lock;

}

return new_mem;

}

是voidtest_free(void*ptr )

{

资产(ptr!=NULL; /*free(null )时,表示程序有困难,直接结束() /

自由(ptr );

pthread_mutex_lock(lock;

--count;

Phread_mutex_unlock(lock;

}

void mem_leak_check_result(void )

{

int temp;

pthread_mutex_lock(lock;

时间=计数;

Phread_mutex_unlock(lock;

是if(temp0)

{

printf (内存leak! \n ';

}

else if (时间==0) ) ) )。

{

printf(nomemeryleak! \n ';

}

else

{

printf(pigsmight尊敬的蓝天! \n ';

}

}

int mem_leak_check_init(void )

{

if(Pthread_mutex_init(lock,NULL )!=0)

{

返回- 1;

}

返回0;

}

void mem _ leak _ check _ destroy (void )

{

Phread_mutex_destroy(lock );

}

上述代码比较简单,所以不附测试用例。 总结几点,就是:

锁定变量count,因为自己封装的test_malloc和test_free必须是线程安全的。

在test_malloc中,调用c库malloc成功时操作count。 下面这样的写法是错误的:

/*错误代码演示*

void*test_malloc(size_tsize ) )。

{

资产(size!=0;

pthread_mutex_lock(lock;

出局;

p>pthread_mutex_unlock(&lock);

return malloc(size);

}

注意在test_malloc中要对传入参数size的校验:

assert(size != 0); 在堆上开辟0字节的内存显然是错误的,操作malloc(0)返回的非NULL指针不合法,会造成踩内存。

注意在test_free中要检测参数为NULL的情况, 虽然free(NULL)合法, 但是明显程序中不应该出现这样的情景。

以上代码同样适用于多进程fork模型, 想一想为什么?

3.如何定位项目中的内存泄漏

通常来说,我们只要找到发生内存泄漏时调用malloc的具体位置, 那么我们就找到了问题所在。接下只需要检查此处malloc该free的地方是否有遗漏即可。

2中的方法很明显不是我们想要的结果, 但却是一个很好的思路, 我们很容易想到这样一种方法:

首先建立一个映射表map, 将调用malloc时所在的文件和行数作为value, malloc调用成功时的返回值作为key, 然后将key:value存入map中; 当调用free时(free中传入的参数ptr即为key) 然后删除map中对应的key。程序正常结束时,我们可以根据map中存储的内容来检查内存泄漏情况:如无内存泄漏, map元素个数是0;如果map中元素个数大于0, 则说明存在内存泄漏, 遍历map, 即可将内存泄漏对应的malloc位置信息输出。

下面给出完整实现代码和测试用例:

/*mem_leak_test.h*/

#ifndef MEM_LEAK_TEST_H

#define MEM_LEAK_TEST_H

#define test_free(p) test_safe_free(__FILE__, __LINE__, p)

#define test_malloc(s) test_safe_malloc(__FILE__, __LINE__, s)

extern void test_safe_free(const char * file, size_t line, void * ptr);

extern void * test_safe_malloc(const char * file, size_t line, size_t size);

extern void mem_leak_test_result(void);

extern int mem_leak_test_init(void);

extern void mem_leak_test_destroy(void);

#endif

/*mem_leak_test.c*/

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include "mem_leak_test.h"

static pthread_mutex_t lock;

static std::map cache;

static void err_exit(const char * info)

{

fprintf(stderr, "%s\n", info);

exit(1);

}

void * test_safe_malloc(const char * file, size_t line, size_t size)

{

void * mem = malloc(size);

assert(size != 0);

if(mem)

{

char buf[266] = {0};

snprintf(buf, sizeof(buf), "file[%s], line[%d]", file, line);

pthread_mutex_lock(&lock);

cache.insert(std::make_pair((unsigned long)mem, buf));

pthread_mutex_unlock(&lock);

}

return mem;

}

void test_safe_free(const char * file, size_t line, void * ptr)

{

size_t cnt;

std::map::iterator it;

assert(ptr != NULL);

free(ptr);

pthread_mutex_lock(&lock);

cnt = cache.erase((unsigned long)ptr);

if(cnt == 0)

{

err_exit("cache.erase nothing");

}

pthread_mutex_unlock(&lock);

}

void mem_leak_test_result(void)

{

std::map::iterator it;

pthread_mutex_lock(&lock);

if(cache.size() == 0)

{

printf("Congratulations, there is no memery leak!\n");

return;

}

printf("memery leak info: \n");

for(it = cache.begin(); it != cache.end(); it++)

{

printf("\tmem addr: %ld, location info: %s\n", it->first, it->second.c_str());

}

pthread_mutex_unlock(&lock);

}

int mem_leak_test_init(void)

{

if(pthread_mutex_init(&lock, NULL) != 0)

{

return -1;

}

return 0;

}

void mem_leak_test_destroy(void)

{

pthread_mutex_destroy(&lock);

}

/*test_main.c*/

#include

#include

#include

#include "mem_leak_test.h"

#define my_malloc(s) test_malloc(s)

#define my_free(p) test_free(p)

#define ARR_SIZE 10

void err_exit(const char * info)

{

fprintf(stderr, "%s\n", info);

exit(1);

}

void test(void)

{

void * arr[ARR_SIZE];

int i;

for(i = 0; i < ARR_SIZE; ++i)

{

arr[i] = NULL;

}

for(i = 0; i < ARR_SIZE; ++i)

{

arr[i] = my_malloc(sizeof(int));

if(!arr[i])

{

err_exit("my_malloc failed!");

}

}

/*there is lack of 2 free() deliberately*/

for(i = 0; i < ARR_SIZE - 2; ++i)

{

my_free(arr[i]);

}

}

int main(int argc, const char * const argv[])

{

/*init memery leak check module*/

if(mem_leak_test_init() != 0)

{

return -1;

}

/*simulate a project which may have a memory leak*/

test();

/*show memery leak check result*/

mem_leak_test_result();

/*destroy memery leak check module*/

mem_leak_test_destroy();

return 0;

}

几点说明:

为了方便演示这里就直接借用c++ STL中的map作为cache。

cache同样需要一把锁来保证数据安全。

为方便传入malloc,free调用处的文件名和行号等信息, 已将test_malloc和test_free定义为宏。(本代码中free对应的文件名和行号等信息暂未用到)

test_main.c中的test()函数模拟存在内存泄漏的项目, 看以看到在其调用过程中故意漏掉了2个free。

程序编译运行结果如下:

study@study-virtual-machine:~/study/c/mem_leak_test$ ls

mem_leak_test.c mem_leak_test.h test_main.c

study@study-virtual-machine:~/study/c/mem_leak_test$ g++ test_main.c mem_leak_test.c -o mem_leak_test

study@study-virtual-machine:~/study/c/mem_leak_test$ ./mem_leak_test

memery leak info:

mem addr: 161508656, location info: file[test_main.c], line[31]

mem addr: 161508752, location info: file[test_main.c], line[31]

study@study-virtual-machine:~/study/c/mem_leak_test$

4.心得和建议

良好的习惯是: 项目中调用malloc或包含有资源申请的模块时应该在旁边注释到哪里应该释放。

测试内存泄漏最容易想到的是程序正常逻辑下的测试, 其实往往内存泄漏的地方都发生在程序异常处理中, 而产生这类异常的原因通常是与外界输入相关的。因此我们在测试项目内存泄漏时要着重测试上述异常条件对应的错误处理分支。

malloc的返回值一定要检查, 尤其在开辟大块内存时或者在内存资源紧缺的嵌入式平台上。虽然malloc失败可能会导致逻辑进行不下去, 但是打印个log也是好事啊!

malloc_trim释放内存,malloc初始化 超前进位加法器真值表,加法器最低位进位为一