网上有很多例子,这里主要依照工作中的使用来记录一下心得。通过搜索可以搜到mcheck、mtrace、valgrind等等各种方法。这里记录一下:
1 mcheck
具体可以搜《Linux系统下借助mcheck实现c/c++程序的堆内存异常检查》这篇文章,比较详细。我比较喜欢用其中的b、c两种:
b. 在makefile中使用-lmcheck来链接程序。优点:无需在源码中显式调用mcheck,且一定可以保证mcheck先于malloc被调用;缺点:程序需要重新编译。 c. 通过设置环境变量MALLOC_CHECK_实现:export MALLOC_CHECK_=0表示检测到的堆内存异常都被忽略;export MALLOC_CHECK_=1表示检测到异常时,向stderr打印相关信息,程序继续运行;export MALLOC_CHECK_=2表示检测到异常时,程序立即abort。定位堆内存问题时,推荐设置为2,这样可以在异常发生时及时保留最近的现场。优点:无需改代码,亦无需重新编译;缺点:需设置环境变量,无法打印出堆内存一致性状态,只是简单的abort进程。
其中b的方法,在实际应用中发现有时会导致进程大量占用内存,具体原因没有查出。
其中c的方法,需要注意进程不能以守护方式后台运行。
2 warp
具体可以搜索《使用__wrap_malloc查看内存使用》这篇文章。
相关代码:
// wrap.c
#include <stdio.h>
#include <stdlib.h>
void* __real_malloc(size_t size); // 只声明不定义__real_malloc
void* __wrap_malloc(size_t size) // 定义__wrap_malloc
{
printf("__wrap_malloc called, size:%zd\n", size); // log输出
return __real_malloc(size); // 通过__real_malloc调用真正的malloc
}
// test.c
#include <stdio.h>
#include <stdlib.h>
int main()
{
char* c = (char*)malloc(sizeof(char)); // 调用malloc
printf("c = %p\n", c);
free(c); // 调用free,防止内存泄漏
return 0;
}
gcc -c wrap.c test.c
gcc -Wl,--wrap,malloc -o test wrap.o test.o // 链接参数-Wl,--wrap,malloc
3 hook
参看 https://www.gnu.org/software/libc/manual/html_node/Hooks-for-Malloc.html 。
在实际项目中,用到的C进程是opensaf拉起来的,涉及到.so和多线程。通过编写实验函数,证明hook的方式,.so中以及子线程中也是有效的。
相关代码:
//test.c
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <malloc.h>
#include "test_so.h"
/* Prototypes for our hooks. */
static void my_init_hook (void);
static void *my_malloc_hook (size_t, const void *);
static void my_free_hook (void*, const void *);
void *old_malloc_hook = NULL;
void *old_free_hook = NULL;
static void
my_init (void)
{
old_malloc_hook = __malloc_hook;
old_free_hook = __free_hook;
__malloc_hook = my_malloc_hook;
__free_hook = my_free_hook;
}
static void *
my_malloc_hook (size_t size, const void *caller)
{
void *result;
/* Restore all old hooks */
__malloc_hook = old_malloc_hook;
__free_hook = old_free_hook;
/* Call recursively */
result = malloc (size);
/* Save underlying hooks */
old_malloc_hook = __malloc_hook;
old_free_hook = __free_hook;
/* printf might call malloc, so protect it too. */
printf ("malloc (%u) returns %p\n", (unsigned int) size, result);
/* Restore our own hooks */
__malloc_hook = my_malloc_hook;
__free_hook = my_free_hook;
return result;
}
static void
my_free_hook (void *ptr, const void *caller)
{
/* Restore all old hooks */
__malloc_hook = old_malloc_hook;
__free_hook = old_free_hook;
/* Call recursively */
free (ptr);
/* Save underlying hooks */
old_malloc_hook = __malloc_hook;
old_free_hook = __free_hook;
/* printf might call free, so protect it too. */
printf ("freed pointer %p\n", ptr);
/* Restore our own hooks */
__malloc_hook = my_malloc_hook;
__free_hook = my_free_hook;
}
void thread(void)
{
int *a = malloc(20);
printf("thread malloc\n");
free(a);
test_so();
return;
}
int main ()
{
pthread_t id;
pthread_create(&id, NULL, (void*)thread, NULL);
my_init();
int *b = malloc(30);
free(b);
pthread_join(id, NULL);
return 0;
}
//test_so.h
void test_sa();
//test_so.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "test_so.h"
void test_so()
{
int *p = malloc(100);
printf("test so malloc!\n");
free(p);
printf("test so free!\n");
return;
}
//编译:
gcc test_so.c -fPIC -shared -o libtest.so
gcc test.c -L. -ltest -lpthread -o test