C 通过宏定义重定义malloc - free,预防内存泄露

简介: C 通过宏定义重定义malloc - free,预防内存泄露

代码地址

GitHub - CHENLitterWhite/CPPWheel: CPP自封装的库

/*
*    作者: 干饭小白
*    时间: 2023-09-25 16:00:00:00
*    
*    说明:
*      只能检测 malloc 和 free,无法检测 new delete
*/
#pragma once
// #define CHECKMEM
#define OPEN_TOTAL_INFO    0x001
#define OPEN_SINGLE_INFO   0x010
#define OPEN_THREAD_INFO   0x100
#include <map>
#include <string>
#include <cstddef>
#include <utility>
#ifdef __cplusplus
extern "C"
{
#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <stdio.h>
#include <sys/shm.h>
#include <unistd.h>
#include <semaphore.h>
};
#endif
struct _gc_info
{
  long _size;
  std::string _content;
  _gc_info()
  {
  }
  _gc_info(long size, std::string con)
  {
    _size = size;
    _content = con;
  }
};
static char Logpath[256] = {0};
static char DirPath[256] = {0};
static std::map<std::string ,_gc_info> total;
volatile static long totalMalloc = 0;
volatile static long totalFree = 0;
volatile static long totalMallocSize = 0;
volatile static long totalFreeSize = 0;
static uint16_t Mode = false;
static sem_t sem_mutex;
extern void get_time(char* str)
{
  time_t now;
  struct tm *local_time;
  now = time(NULL);
  local_time = localtime(&now);
  sprintf(str, "%d-%02d-%02d_%02d:%02d:%02d", 
            local_time->tm_year + 1900, local_time->tm_mon + 1, local_time->tm_mday,
            local_time->tm_hour, local_time->tm_min, local_time->tm_sec);
  return;
}
extern void init_gc(const char* dirPath, uint16_t mode = OPEN_TOTAL_INFO)
{
    sem_init(&sem_mutex, 0, 1);
    struct stat st;
    if (stat(dirPath, &st) == 0 && S_ISDIR(st.st_mode))
    {
        // printf("文件夹已存在\n");
    }
    else 
    {
        if(mkdir(dirPath, 0777) != 0)
        {
            return;
        } 
    }
    Mode = mode;
    strncpy(DirPath, dirPath, 256);
    char time[256] = {0};
    get_time(time);
    sprintf(Logpath, "%s/%s_total.log", dirPath, time);
    unlink(Logpath);
    char buff[128] = {0};
    sprintf(buff, "%s/thread.log", DirPath);  
    unlink(buff);
    return;
}
extern void total_gc()
{
    sem_destroy (&sem_mutex);
    if((Mode & OPEN_TOTAL_INFO) == OPEN_TOTAL_INFO)
    {
        FILE *fp = fopen(Logpath, "a+w");
        fprintf(fp, "\n=========================================\n");
        fprintf(fp, "申请次数:%ld\n", totalMalloc);
        fprintf(fp, "释放次数:%ld\n", totalFree);
        fprintf(fp, "申请总大小:%ld\n", totalMallocSize);
        fprintf(fp, "释放总大小:%ld\n", totalFreeSize);
        fprintf(fp, "未释放总大小:%ld\n", totalMallocSize - totalFreeSize);
        fprintf(fp, "问题统计:%ld\n", total.size());
        fprintf(fp, "=========================================\n");
        fflush(fp);
        for(auto it = total.begin(); it != total.end(); ++it)
        {
            fprintf(fp, "%s", it->second._content.c_str());
            fflush(fp);
        }
        fclose(fp);
    }
    total.clear();
}
extern void* malloc_gc(size_t size, const char* file, const char* func, int line)
{
    sem_wait(&sem_mutex);
    FILE *test = NULL;
    if((Mode & OPEN_THREAD_INFO) == OPEN_THREAD_INFO)
    {   
        char buff[128] = {0};
        sprintf(buff, "%s/thread.log", DirPath);
        test = fopen(buff, "a+w");
        fprintf(test, "ERROR 进入malloc_gc--->%ld\n", pthread_self());
        fflush(test);  
    }
    void* p =malloc(size);
    char time[256] = {0};
    get_time(time);
    FILE *fp = NULL;
    if((Mode & OPEN_SINGLE_INFO) == OPEN_SINGLE_INFO)
    {
        char buff[128] = {0};
        sprintf(buff, "%s/%p.log", DirPath,p);
        FILE *fp = fopen(buff, "w");
        fprintf(fp, "%s:ERROR [+%s:%s:%d][PID:%ld] --> ADDR:%p, size:%ld\n", time, file, func, line, pthread_self() , p, size);
        fflush(fp);
        fclose(fp);
    }
    if((Mode & OPEN_TOTAL_INFO) == OPEN_TOTAL_INFO)
    {
        totalMallocSize+= size;
        fp = fopen(Logpath, "a+w");
        fprintf(fp, "%s:[+%s:%s:%d][PID:%ld] --> ADDR:%p, size:%ld\n", time, file, func, line, pthread_self(), p, size);
        fflush(fp);
        fclose(fp);
        char content[256] = {0};
        sprintf(content, "%s:ERROR [+!%s:%s:%d][PID:%ld] 内存泄漏 --> ADDR:%p, size:%ld\n", time, file, func, line, pthread_self(), p, size);
        char addr[128] = {0};
        sprintf(addr, "%p", p);
        _gc_info info(size, content);
        total.insert(std::make_pair(addr, info));
        totalMalloc++;
    }
    if((Mode & OPEN_THREAD_INFO) == OPEN_THREAD_INFO)
    { 
        fprintf(test, "INFO  离开malloc_gc--->%ld\n", pthread_self());
        fflush(test);  
        fclose(test);
    }
    sem_post(&sem_mutex);
    return p;
}
extern void free_gc(void* p, const char* file, const char* func, int line)
{
    sem_wait(&sem_mutex);  
    FILE *test = NULL;
    if((Mode & OPEN_THREAD_INFO) == OPEN_THREAD_INFO)
    { 
        char buff[128] = {0};
        sprintf(buff, "%s/thread.log", DirPath);
        test = fopen(buff, "a+w");
        fprintf(test, "ERROR 进入free_gc--->%ld\n", pthread_self());
        fflush(test);  
    }
    char time[256] = {0};
    get_time(time);
    if((Mode & OPEN_TOTAL_INFO) == OPEN_TOTAL_INFO)
    {
        totalFree++;
        char addr[128] = {0};
        sprintf(addr, "%p", p);
        if(total.find(addr) == total.end())
        {
            char content[256] = {0};
            sprintf(content, "%s:ERROR [-!%s:%s:%d][PID:%ld] 二次释放 --> ADDR:%p\n", time, file, func, line, pthread_self(), p);
            char addr[128] = {0};
            sprintf(addr, "%p", p);
            _gc_info info(0, content);
            sem_post(&sem_mutex);
            total.insert(std::make_pair(addr, info));
        }
        else 
        {
            totalFreeSize += total[addr]._size;
            FILE* fp = fopen(Logpath, "a+w");
            fprintf(fp, "%s:[-%s:%s:%d][PID:%ld] --> ADDR:%p, size:%ld\n", time, file, func, line, pthread_self(), p, total[addr]._size);
            fflush(fp);
            fclose(fp);
            total.erase(addr);
            free(p);
        }
    }
    char buff[128] = {0};
    sprintf(buff, "%s/%p.log", DirPath,p);
    if((Mode & OPEN_SINGLE_INFO) == OPEN_SINGLE_INFO && unlink(buff) < 0)
    {
        FILE *fp = fopen(buff, "w");
        fprintf(fp, "%s:ERROR [-!%s:%s:%d][PID:%ld] 二次释放 --> ADDR:%p\n", time, file, func, line, pthread_self(), p);
        fflush(fp);
        fclose(fp);
    }
    if((Mode & OPEN_THREAD_INFO) == OPEN_THREAD_INFO)
    {
        fprintf(test, "INFO  离开free_gc--->%ld\n", pthread_self());
        fflush(test);  
        fclose(test);
    }
    sem_post(&sem_mutex);
    return;
}
#ifdef CHECKMEM
#define malloc(size) malloc_gc(size, __FILE__, __FUNCTION__, __LINE__)
#define free(p) free_gc(p, __FILE__, __FUNCTION__, __LINE__)
#endif

相关说明

1.不支持new 和 delete。尝试过,发现效果不好,new本身内部会malloc和free,想要支持多线程,容易加锁两次。delete不方便宏替换。

2.支持多线程,不支持多进程,如果想要支持多进程,相关的控制部分定义到共享内存中

3.定义CHECKMEM,开启内存检查

使用案例

#include "mem.h"
int main()
{
    init_gc("./mem", OPEN_TOTAL_INFO | OPEN_SINGLE_INFO | OPEN_THREAD_INFO);
    void* p1 = malloc(1);
    void* p2 = malloc(1);
    void* p3 = malloc(1);
    free(p1);
    free(p2);
    free(p2);
    total_gc();
    return 0;
}

部分效果图

多线程下定位具体线程 ==> OPEN_THREAD_INFO

统计信息 ==> OPEN_TOTAL_INFO

单文件快速定位 ==> OPEN_SINGLE_INFO

相关文章
|
2月前
|
监控 Java 数据库连接
解析与预防:Java中的内存泄漏问题
解析与预防:Java中的内存泄漏问题
|
2月前
关于为什么要在链表中用malloc来分配内存
关于为什么要在链表中用malloc来分配内存
|
6天前
|
编译器
练习使用动态内存相关的4个函数:malloc、calloc、realloc、free
在了解使用动态内存相关的四个函数之前,我们先了解一下,为什么要有动态内存分配?
14 0
|
7天前
|
缓存 Linux
linux性能分析之内存分析(free,vmstat,top,ps,pmap等工具使用介绍)
这些工具可以帮助你监视系统的内存使用情况、识别内存泄漏、找到高内存消耗的进程等。根据具体的问题和需求,你可以选择使用其中一个或多个工具来进行内存性能分析。注意,内存分析通常需要综合考虑多个指标和工具的输出,以便更好地理解系统的行为并采取相应的优化措施。
27 6
|
17天前
|
程序员 编译器 C语言
C语言知识:动态内存管理(malloc free calloc realloc)
C语言知识:动态内存管理(malloc free calloc realloc)
|
1月前
|
Java 程序员 编译器
C语言中灵活多变的动态内存,malloc函数 && free函数&& calloc函数 && realloc函数
C语言中灵活多变的动态内存,malloc函数 && free函数&& calloc函数 && realloc函数
|
1月前
|
程序员 编译器 C语言
【C语言】动态内存管理之4个内存函数`malloc`,`free`,`calloc`和`realloc`深度了解
【C语言】动态内存管理之4个内存函数`malloc`,`free`,`calloc`和`realloc`深度了解
|
1月前
|
存储 缓存 监控
深入解析linux内存指标:快速定位系统内存问题的有效技巧与实用方法(free、top、ps、vmstat、cachestat、cachetop、sar、swap、动态内存、cgroops、oom)
深入解析linux内存指标:快速定位系统内存问题的有效技巧与实用方法(free、top、ps、vmstat、cachestat、cachetop、sar、swap、动态内存、cgroops、oom)
194 0
|
2月前
|
存储 缓存 Shell
【Shell 命令集合 系统管理 】⭐⭐⭐Linux 显示系统内存的使用情况 free命令 使用指南
【Shell 命令集合 系统管理 】⭐⭐⭐Linux 显示系统内存的使用情况 free命令 使用指南
29 0
|
2月前
|
存储 程序员 Shell
【C/C++ 内存管理函数】C语言动态内存管理大揭秘:malloc、calloc、realloc与new的对比与差异
【C/C++ 内存管理函数】C语言动态内存管理大揭秘:malloc、calloc、realloc与new的对比与差异
178 0