内存泄漏检测组件的实现

简介: 内存泄漏检测组件的实现
  1. 通过宏定义来包装 mallocfree 函数,以便在每次内存分配和释放时记录相关信息,如文件名和行号。这使得你能够跟踪哪个函数在哪里分配和释放内存。
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <link.h>
// 方式一:宏定义
void *_malloc(size_t size, char *filename,int line) {
    void *ptr = malloc(size);
    char file[128] = {0};
    sprintf(file ,"./mem/%p.mem" ,ptr);
    FILE *fp = fopen(file ,"w");//w小写
    fprintf(fp, "[+]addr: %p filename: %s line: %d\n",ptr,filename,line);
    fflush(fp);
    fclose(fp);
    return ptr;
}
void _free(void *ptr, char *filename,int line) {
    char file[128] = {0};
    sprintf(file,"./mem/%p.mem",ptr);
    if(unlink(file) < 0){//unlink用于在文件系统中删除指定的文件
        printf("double free %p\n",ptr);
        return;
    }
    return free(ptr);
}
// __FILE__ 获取文件名
// __LINE__ 获取函数执行的行号
#define malloc(size)   _malloc(size, __FILE__,__LINE__)
#define free(ptr)      _free(ptr, __FILE__,__LINE__)
int main(void) {
    init_hook();
    void *p1 = malloc(8);
    void *p2 = malloc(16);
    void *p3 = malloc(32);
    free(p1);
    free(p2);
    return 0;
}

编译执行:

表示在memleak.c 文件中, 第149行出现内存泄漏问题。

2.通过使用hook方法来重定向 mallocfree 函数, 与此同时通过__builtin_return_address()函数的返回值结合(*caller) 命令: addr2line -f -e ./程序名 -a 返回值(caller) 查看内存泄露的程序及具体行数。

#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <link.h>
//方式二:hook
// gcc -o memleak memleak.c -g -ldl
// addr2line -f -e ./memleak -a 0x400b38(返回值)
typedef void *(*malloc_t)(size_t size);
malloc_t malloc_f = NULL;
typedef void (*free_t)(void *ptr);
free_t free_f = NULL;
int enable_malloc_hook = 1;
int enable_free_hook = 1;
void *COnvertToELF(void *addr) {
  Dl_info info;
  struct link_map *link;
  dladdr1(addr, &info, (void**)&link,RTLD_DL_LINKMAP);
  return (void*)((size_t)addr - link->l_addr);
}
void *malloc(size_t size) {
  void *ptr = NULL;
  if (enable_malloc_hook) {
    enable_malloc_hook = 0;
    ptr = malloc_f(size);
  // main --> f1() --> f2() --> f3() { __builtin_return_address(0)  }
    void *caller = __builtin_return_address(0);
    char filename[128] = {0};
    sprintf(filename, "./mem/%p.mem", ptr);
    FILE *fp = fopen(filename, "w");
    fprintf(fp, "[+] caller: %p, addr: %p, size: %ld\n",
       COnvertToELF(caller), ptr, size);
    fflush(fp);
    enable_malloc_hook = 1;
  } else {
    ptr = malloc_f(size);
  }
  return ptr;
}
void free(void *ptr) {
  if (enable_free_hook) {
    enable_free_hook = 0;
        char file[128] = {0};
    sprintf(file, "./mem/%p.mem", ptr);
    if (unlink(file) < 0) { // filename no exist;
      printf("double free: %p\n", ptr);
      return ;
    }
    free_f(ptr);
    enable_free_hook = 1;
  } else {
    free_f(ptr);
  }
}
void init_hook(void) {
  if (!malloc_f) {
    malloc_f = dlsym(RTLD_NEXT, "malloc");
  }
  if (!free_f) {
    free_f = dlsym(RTLD_NEXT, "free");
  }
}
int main(void) {
    init_hook();
    void *p1 = malloc(8);
    void *p2 = malloc(16);
    void *p3 = malloc(32);
    free(p1);
    free(p2);
    return 0;
}

编译执行:

表示在memleak.c 文件的 main 函数中, 第149行出现内存泄漏问题。

源文件 memleak.c

#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <link.h>
// 方式一:宏定义
#if 0
void *_malloc(size_t size, char *filename,int line) {
    void *ptr = malloc(size);
    char file[128] = {0};
    sprintf(file ,"./mem/%p.mem" ,ptr);
    FILE *fp = fopen(file ,"w");//w小写
    fprintf(fp, "[+]addr: %p filename: %s line: %d\n",ptr,filename,line);
    fflush(fp);
    fclose(fp);
    return ptr;
}
void _free(void *ptr, char *filename,int line) {
    char file[128] = {0};
    sprintf(file,"./mem/%p.mem",ptr);
    if(unlink(file) < 0){//unlink用于在文件系统中删除指定的文件
        printf("double free %p\n",ptr);
        return;
    }
    return free(ptr);
}
// __FILE__ 获取文件名
// __LINE__ 获取函数执行的行号
#define malloc(size)   _malloc(size, __FILE__,__LINE__)
#define free(ptr)      _free(ptr, __FILE__,__LINE__)
//方式二:hook
#elif 1
// gcc -o memleak memleak.c -g -ldl
// addr2line -f -e ./memleak -a 0x400b38
typedef void *(*malloc_t)(size_t size);
malloc_t malloc_f = NULL;
typedef void (*free_t)(void *ptr);
free_t free_f = NULL;
int enable_malloc_hook = 1;
int enable_free_hook = 1;
void *COnvertToELF(void *addr) {
  Dl_info info;
  struct link_map *link;
  dladdr1(addr, &info, (void**)&link,RTLD_DL_LINKMAP);
  return (void*)((size_t)addr - link->l_addr);
}
void *malloc(size_t size) {
  void *ptr = NULL;
  if (enable_malloc_hook) {
    enable_malloc_hook = 0;
    ptr = malloc_f(size);
  // main --> f1() --> f2() --> f3() { __builtin_return_address(0)  }
    void *caller = __builtin_return_address(0);
    char filename[128] = {0};
    sprintf(filename, "./mem/%p.mem", ptr);
    FILE *fp = fopen(filename, "w");
    fprintf(fp, "[+] caller: %p, addr: %p, size: %ld\n",
       COnvertToELF(caller), ptr, size);
    fflush(fp);
    enable_malloc_hook = 1;
  } else {
    ptr = malloc_f(size);
  }
  return ptr;
}
void free(void *ptr) {
  if (enable_free_hook) {
    enable_free_hook = 0;
        char file[128] = {0};
    sprintf(file, "./mem/%p.mem", ptr);
    if (unlink(file) < 0) { // filename no exist;
      printf("double free: %p\n", ptr);
      return ;
    }
    free_f(ptr);
    enable_free_hook = 1;
  } else {
    free_f(ptr);
  }
}
void init_hook(void) {
  if (!malloc_f) {
    malloc_f = dlsym(RTLD_NEXT, "malloc");
  }
  if (!free_f) {
    free_f = dlsym(RTLD_NEXT, "free");
  }
}
#endif
#if 1
int main(void) {
    init_hook();
    void *p1 = malloc(8);
    void *p2 = malloc(16);
    void *p3 = malloc(32);
    free(p1);
    free(p2);
    return 0;
}
#endif

注意:提前在程序目录下创建mem文件夹,编译时添加 -g -ldl

具体使用时只需将该文件的main函数注释掉,与需要检测的程序源文件一起编译执行即可。

目录
相关文章
|
21天前
|
缓存 算法 Java
本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制
在现代软件开发中,性能优化至关重要。本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制。通过调整垃圾回收器参数、优化堆大小与布局、使用对象池和缓存技术,开发者可显著提升应用性能和稳定性。
40 6
|
29天前
|
Web App开发 JavaScript 前端开发
使用 Chrome 浏览器的内存分析工具来检测 JavaScript 中的内存泄漏
【10月更文挑战第25天】利用 Chrome 浏览器的内存分析工具,可以较为准确地检测 JavaScript 中的内存泄漏问题,并帮助我们找出潜在的泄漏点,以便采取相应的解决措施。
161 9
|
29天前
|
监控 JavaScript 前端开发
如何检测和解决 JavaScript 中内存泄漏问题
【10月更文挑战第25天】解决内存泄漏问题需要对代码有深入的理解和细致的排查。同时,不断优化和改进代码的结构和逻辑也是预防内存泄漏的重要措施。
41 6
|
1月前
|
Web App开发 缓存 JavaScript
如何检测和解决闭包引起的内存泄露
闭包引起的内存泄露是JavaScript开发中常见的问题。本文介绍了闭包导致内存泄露的原因,以及如何通过工具检测和代码优化来解决这些问题。
|
3月前
|
C语言 Android开发 C++
基于MTuner软件进行qt的mingw编译程序的内存泄漏检测
本文介绍了使用MTuner软件进行Qt MinGW编译程序的内存泄漏检测的方法,提供了MTuner的下载链接和测试代码示例,并通过将Debug程序拖入MTuner来定位内存泄漏问题。
基于MTuner软件进行qt的mingw编译程序的内存泄漏检测
|
2月前
|
Web App开发 开发者
|
2月前
|
缓存 监控 Java
内存泄漏:深入理解、检测与解决
【10月更文挑战第19天】内存泄漏:深入理解、检测与解决
60 0
|
2月前
|
设计模式 Java Android开发
安卓应用开发中的内存泄漏检测与修复
【9月更文挑战第30天】在安卓应用开发过程中,内存泄漏是一个常见而又棘手的问题。它不仅会导致应用运行缓慢,还可能引发应用崩溃,严重影响用户体验。本文将深入探讨如何检测和修复内存泄漏,以提升应用性能和稳定性。我们将通过一个具体的代码示例,展示如何使用Android Studio的Memory Profiler工具来定位内存泄漏,并介绍几种常见的内存泄漏场景及其解决方案。无论你是初学者还是有经验的开发者,这篇文章都将为你提供实用的技巧和方法,帮助你打造更优质的安卓应用。
|
2月前
|
数据处理 Python
Python读取大文件的“坑“与内存占用检测
Python读取大文件的“坑“与内存占用检测
53 0
|
2月前
|
存储 算法 C语言
MacOS环境-手写操作系统-15-内核管理 检测可用内存
MacOS环境-手写操作系统-15-内核管理 检测可用内存
43 0