【检测内存泄漏的几种方法 C】

简介: 【检测内存泄漏的几种方法 C】
//#define __USE_GNU
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <malloc.h>
#include <mcheck.h>
#if 0
extern void *__libc_malloc(size_t size);
int enable_malloc_hook = 1;
extern void __libc_free(void* p);
int enable_free_hook = 1;
// func --> malloc() { __builtin_return_address(0)}
// callback --> func --> malloc() { __builtin_return_address(1)}
// main --> callback --> func --> malloc() { __builtin_return_address(2)}
//calloc, realloc
void *malloc(size_t size) {
  if (enable_malloc_hook) {
    enable_malloc_hook = 0;
    void *p = __libc_malloc(size);
    void *caller = __builtin_return_address(1); // 1
    char buff[128] = {0};
    sprintf(buff, "./mem/%p.mem", p);
    FILE *fp = fopen(buff, "w");
    fprintf(fp, "[+%p] --> addr:%p, size:%ld\n", caller, p, size);
    fflush(fp);
    //fclose(fp); //free
    enable_malloc_hook = 1;
    return p;
  } else {
    return __libc_malloc(size);
  }
  return NULL;
}
void free(void *p) {
  if (enable_free_hook) {
    enable_free_hook = 0;
    char buff[128] = {0};
    sprintf(buff, "./mem/%p.mem", p);
    if (unlink(buff) < 0) { // no exist
      printf("double free: %p\n", p);
    }
    __libc_free(p);
    // rm -rf p.mem
    enable_free_hook = 1;
  } else {
    __libc_free(p);
  }
}
#elif 0
void *malloc_hook(size_t size, const char *file, int line) {
  void *p = malloc(size);
  char buff[128] = {0};
  sprintf(buff, "./mem/%p.mem", p);
  FILE *fp = fopen(buff, "w");
  fprintf(fp, "[+%s:%d] --> addr:%p, size:%ld\n", file, line, p, size);
  fflush(fp); 
  fclose(fp);
  return p;
}
void free_hook(void *p, const char *file, int line) {
  char buff[128] = {0};
  sprintf(buff, "./mem/%p.mem", p);
  if (unlink(buff) < 0) { // no exist
    printf("double free: %p\n", p);
    return ;
  }
  free(p);
}
#if 1
#define malloc(size)  malloc_hook(size, __FILE__, __LINE__)
#define free(p)     free_hook(p, __FILE__, __LINE__)
#endif
#elif 1
typedef void *(*malloc_hook_t)(size_t size, const void *caller);
malloc_hook_t malloc_f;
typedef void (*free_hook_t)(void *p, const void *caller);
free_hook_t free_f;
int replaced = 0;
void mem_trace(void);
void mem_untrace(void);
void *malloc_hook_f(size_t size, const void *caller) {
  mem_untrace();
  void *ptr = malloc(size);
  //printf("+%p: addr[%p]\n", caller, ptr);
  char buff[128] = {0};
  sprintf(buff, "./mem/%p.mem", ptr);
  FILE *fp = fopen(buff, "w");
  fprintf(fp, "[+%p] --> addr:%p, size:%ld\n", caller, ptr, size);
  fflush(fp);
  fclose(fp); //free
  mem_trace();
  return ptr;
}
void *free_hook_f(void *p, const void *caller) {
  mem_untrace();
  //printf("-%p: addr[%p]\n", caller, p);
  char buff[128] = {0};
  sprintf(buff, "./mem/%p.mem", p);
  if (unlink(buff) < 0) { // no exist
    printf("double free: %p\n", p);
    return ;
  }
  free(p);
  mem_trace();
}
void mem_trace(void) { //mtrace
  replaced = 1;
  malloc_f = __malloc_hook; //malloc --> 
  free_f = __free_hook;
  __malloc_hook = malloc_hook_f;
  __free_hook = free_hook_f;
}
void mem_untrace(void) {
  __malloc_hook = malloc_f;
  __free_hook = free_f;
  replaced = 0;
}
#endif
/*
 @ ./memleak:[0x400645] + 0x257c450 0x14
 */
// addr2line -f -e memleak -a 0x4006f7
int main() {
#if 0
  void *p1 = malloc(10);
  void *p2 = malloc(20); //calloc, realloc
  free(p1);
  void *p3 = malloc(20);
  void *p4 = malloc(20);
  free(p2);
  free(p4);
  //free(p4);
#elif 1
  mem_trace();
  void *p1 = malloc(10);
  void *p2 = malloc(20); //calloc, realloc
  free(p1);
  void *p3 = malloc(20);
  void *p4 = malloc(20);
  free(p2);
  free(p4);
  mem_untrace();
#else
  mtrace();
  void *p1 = malloc(10);
  void *p2 = malloc(20); //calloc, realloc
  free(p1);
  void *p3 = malloc(20);
  void *p4 = malloc(20);
  free(p2);
  free(p4);
  muntrace();
#endif
  return 0;
}
相关文章
|
2天前
|
存储 Java C++
C++ 引用和指针:内存地址、创建方法及应用解析
C++中的引用是现有变量的别名,创建时需用`&`运算符,如`string &meal = food;`。指针存储变量的内存地址,使用`*`创建,如`string* ptr = &food;`。引用必须初始化且不可为空,而指针可初始化为空。引用在函数参数传递和提高效率时有用,指针适用于动态内存分配和复杂数据结构操作。选择使用取决于具体需求。
41 9
|
2天前
|
存储 缓存 Java
嵌入式系统中C++内存管理基本方法
嵌入式系统中C++内存管理基本方法
93 0
|
2天前
|
存储 算法
【三种方法】求一个整数存储在内存中二进制中的1的个数附两道课外练习题
【三种方法】求一个整数存储在内存中二进制中的1的个数附两道课外练习题
10 0
|
2天前
|
编译器 C++
C++ 解引用与函数基础:内存地址、调用方法及声明
C++ 中的解引用允许通过指针访问变量值。使用 `*` 运算符可解引用指针并修改原始变量。注意确保指针有效且不为空,以防止程序崩溃。函数是封装代码的单元,用于执行特定任务。理解函数的声明、定义、参数和返回值是关键。函数重载允许同一名称但不同参数列表的函数存在。关注公众号 `Let us Coding` 获取更多内容。
138 1
|
2天前
|
存储 缓存 监控
深入解析linux内存指标:快速定位系统内存问题的有效技巧与实用方法(free、top、ps、vmstat、cachestat、cachetop、sar、swap、动态内存、cgroops、oom)
深入解析linux内存指标:快速定位系统内存问题的有效技巧与实用方法(free、top、ps、vmstat、cachestat、cachetop、sar、swap、动态内存、cgroops、oom)
218 0
|
2天前
|
存储 缓存 监控
探秘Linux系统内存问题:主体 进程RSS均正常但系统内存下降的调查方法
探秘Linux系统内存问题:主体 进程RSS均正常但系统内存下降的调查方法
78 0
|
2天前
|
存储 安全 编译器
C++智能指针:更简单、更高效的内存管理方法
C++智能指针:更简单、更高效的内存管理方法
32 0
|
2天前
|
人工智能 自然语言处理 物联网
极大降低大模型训练内存需求,Meta等推出高效方法
【2月更文挑战第27天】极大降低大模型训练内存需求,Meta等推出高效方法
39 2
极大降低大模型训练内存需求,Meta等推出高效方法
|
2天前
|
存储 Linux 编译器
Linux用户空间和内核空间所有15种内存分配方法
Linux用户空间和内核空间所有15种内存分配方法
94 1
|
2天前
|
存储 搜索推荐 Serverless
用指针和动态内存分配的方法输入10,2,30, 4,5,按输入顺序逆置排序,输出排序后的元素,即输出5,4,30,2,10
用指针和动态内存分配的方法输入10,2,30, 4,5,按输入顺序逆置排序,输出排序后的元素,即输出5,4,30,2,10
19 0