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

news2024/11/20 20:37:30

系列文章目录

C++模版基础


文章目录

目录

代码地址

相关说明

使用案例 



代码地址

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1017373.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[Linux入门]---Linux指令②

文章目录 Linux系统常用指令1.man指令2.echo3.cp指令&#xff08;重要&#xff09;4.mv指令&#xff08;重要&#xff09;&#xff1a;5.alias指令6.cat指令7.more指令8.less指令&#xff08;重要&#xff09;9.head指令10.tail指令11.时间相关的指令1.在显示方面2.在设定时间方…

Redis环境配置

【Redis解压即可】链接&#xff1a;https://pan.baidu.com/s/1y4xVLF8-8PI8qrczbxde9w?pwd0122 提取码&#xff1a;0122 【Redis桌面工具】 链接&#xff1a;https://pan.baidu.com/s/1IlsUy9sMfh95dQPeeM_1Qg?pwd0122 提取码&#xff1a;0122 Redis安装步骤 1.先打开Redis…

OpenAI开发系列(二):大语言模型发展史及Transformer架构详解

全文共1.8w余字&#xff0c;预计阅读时间约60分钟 | 满满干货&#xff0c;建议收藏&#xff01; 一、介绍 在2020年秋季&#xff0c;GPT-3因其在社交媒体上病毒式的传播而引发了广泛关注。这款拥有超过1.75亿参数和每秒运行成本达到100万美元的大型语言模型&#xff08;Large …

【力扣周赛】第 362 场周赛(⭐差分匹配状态压缩DP矩阵快速幂优化DPKMP)

文章目录 竞赛链接Q1&#xff1a;2848. 与车相交的点解法1——排序后枚举解法2——差分数组⭐差分数组相关题目列表&#x1f4d5;1094. 拼车1109. 航班预订统计2381. 字母移位 II2406. 将区间分为最少组数解法1——排序贪心优先队列解法2——差分数组 2772. 使数组中的所有元素…

加密算法发展简介

1&#xff1a;对称加密算法 客户端加密数据和服务端解密数据&#xff0c;使用的相同的秘钥&#xff1a; 固定秘钥&#xff1a;双方约定好一个固定秘钥&#xff1b; 随机秘钥&#xff1a;双方约定每次建立连接的时候&#xff0c;某固定BYTE为秘钥&#xff1b; 缺点&#xff1a…

【MySQL】 MySQL数据库基础

文章目录 &#x1f431;‍&#x1f453;数据库的操作&#x1f4cc;显示当前的数据库&#x1f4cc;创建数据库&#x1f388;语法&#xff1a;&#x1f388;语法说明&#x1f388;示例&#xff1a; &#x1f334;使用数据库&#x1f38b;删除数据库&#x1f431;‍&#x1f3cd;语…

sql注入Less-2

后台sql s q l " S E L E C T ∗ F R O M u s e r s W H E R E i d sql "SELECT * FROM users WHERE id sql"SELECT∗FROMusersWHEREidid LIMIT 0,1"; 注入语句 http://192.168.200.26/Less-3/?id-1? union select 1,2,database();– 使用id-1 便可…

JavaScript中的Hoisting机制

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ JavaScript 中的 Hoisting 机制⭐ 变量提升⭐ 函数提升⭐ 注意事项⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xf…

LVS+Keepalived 高可用集群

LVSKeepalived 高可用集群 1、Keepalived工具介绍2、vrrp协议&#xff08;虚拟路由冗余协议&#xff09;2.1vrrrp是什么&#xff1f;2.2vrrp工作过程2.3Keeplived、VRRP及其工作原理2.4Keepalived体系主要模块 3、搭建LVSKeepalived 高可用集群 1、Keepalived工具介绍 支持故障…

MFC-GetSystemFirmwareTable获取系统固件表

获取ACPI表格 void CgetSystemFirmwareTableDlg::OnBnClickedButton1() {//UINT bufferSize GetSystemFirmwareTable(ACPI, 0, NULL, 0);//获取系统固件表/*【参数3和参数4为NULL和0&#xff0c;只是为了返回真实大小】这个函数可以用来获得系统中的各种固件信息&#xff0c;如…

MySQL中SQL语句执行顺序分析

1、 MySQL手写执行顺序 2、 MySQL机读执行顺序 随着Mysql版本的更新换代&#xff0c;其优化器也在不断的升级&#xff0c;优化器会分析不同执行顺序产生的性能消耗不同而动态调整执行顺序。下面是经常出现的查询顺序&#xff1a;

SpringBoot使用Mybatis查询数据

1.创建工程 说明&#xff1a;创建springboot工程&#xff0c;数据库表book&#xff0c;实体类Book 1.1创建项目 1.2 勾选相应的配置 1.3数据表book 说明&#xff1a;创建了book表&#xff0c;添加了id,type,name,description字段。 1.4创建Book实体类 说明&#xff1a;生成…

微服务保护-流控效果

个人名片&#xff1a; 博主&#xff1a;酒徒ᝰ. 个人简介&#xff1a;沉醉在酒中&#xff0c;借着一股酒劲&#xff0c;去拼搏一个未来。 本篇励志&#xff1a;三人行&#xff0c;必有我师焉。 本项目基于B站黑马程序员Java《SpringCloud微服务技术栈》&#xff0c;SpringCloud…

【AI】推理系统和推理引擎的整体架构

本文主要是对 B 站 Up 主 ZOMI酱 推理系统系列视频 的理解&#xff0c;可以认为是重点笔记。 一、深度学习模型的全生命周期 相信很多人和我一样&#xff0c;刚看到深度学习模型中的推理系统或推理引擎时是一头雾水&#xff0c;因为学习 DL 时通常关注于模型的设计和训练。下图…

MFC - 一文带你从小白到项目应用(全套1)

文章篇幅可能会比较长&#xff0c;从入门到基本能上项目的全部内容。建议观看的过程中&#xff0c;用电脑跟着学习案例。 持续输出优质文章是作者的追求&#xff0c;因为热爱&#xff0c;所以热爱。 最近看动漫被一句鸡汤感动到了&#xff0c;也送给各位朋友&#xff1a; 只要有…

微服务保护-热点参数限流

个人名片&#xff1a; 博主&#xff1a;酒徒ᝰ. 个人简介&#xff1a;沉醉在酒中&#xff0c;借着一股酒劲&#xff0c;去拼搏一个未来。 本篇励志&#xff1a;三人行&#xff0c;必有我师焉。 本项目基于B站黑马程序员Java《SpringCloud微服务技术栈》&#xff0c;SpringCloud…

Dubbo3基础使用

1、Dubbo概述 现在SpringCloud Alibaba比较火&#xff0c;用的比较多是吧&#xff0c;那dubbo是不是过时的呢&#xff1f; 并不是的&#xff0c;以前有人把Dubbo和SpringCloud进行对比&#xff0c;其实两者是不同维度的&#xff0c;不能对比&#xff0c;dubbo就是一个rpc框架&…

Adobe Bridge 2024:解锁创意力的数字媒体利器

在当今数字化的时代&#xff0c;创意工作者们需要处理和管理大量的数字媒体资源&#xff0c;如照片、视频、音频等。为了提高工作效率和创作质量&#xff0c;他们需要一个功能强大、易于使用的工具来组织、浏览和共享这些媒体文件。幸运的是&#xff0c;Adobe Bridge 2024 正好…

Linux文件类型与根目录结构

目录 一、文件类型 二、目录结构 1、FHS Linux目录结构的特点 2、路径以及工作目录 1&#xff09;路径 2&#xff09;工作目录 3&#xff09;存放路径 一、文件类型 主目录下部分文件如下&#xff1a; [rootlocalhost ~]# cd ~ [rootlocalhost ~]# ll total 52 -rw-r--…

烟雾报警系统设计与实现

摘要 随着“信息时代”的到来&#xff0c;作为获取信息的手段——传感器技术得到了显著的进步&#xff0c;其应用领域越来越广泛&#xff0c;对其要求越来越高&#xff0c;需求越来越迫切。传感器技术已成为衡量一个国家科学技术发展水平的重要标志之一。因此&#xff0c;了解…