内存泄漏检测组建与mmap内存共享

文章介绍了多种检测和管理内存泄漏的方法,包括使用valgrind和mtrace工具,以及通过宏定义和自定义malloc/free函数来追踪内存分配和释放。此外,还提供了两种不同的共享内存实现方式,一种是通过mmap匿名映射,另一种是映射/dev/zero文件。
摘要由CSDN通过智能技术生成

内存泄漏

常见检测工具 valgrind,mtrace
该组件解决:
A 如何知道内存泄漏?
B 如何定位代码哪一行引起内存泄漏?
解决方案:
终端命令:addr2line -f -e (执行文件名字) -a (这里写caller地址)

版本1

A 简单做法
malloc/calloc/realloc +1
free -1
判断进程结束前是否为0;
C语言有一些宏可以知道哪一行
-file-,-func-,-LINE-
底层是调用了 builtin_return_address()函数
builtin_return_address(),该函数参数表示返回哪一个函数
注意malloc()会调用builtin_return_address()
例:

fun1(){
	fun2(){
		fun3(){
			malloc();
		}
	}
}

builtin_return_address(0)》返回的是fun3
builtin_return_address(1)
》返回的是fun2
builtin_return_address(2)==》返回的是fun1
等等
代码如下

//版本1 调用系统函数
// __libc_malloc(){}//更底层的函数
extern void* __libc_malloc(size_t size);
int enable_malloc_hook = 1;
void *malloc(size_t size){
    //递归终止直接打印会递归死循环,是由于printf中也会调用malloc,gbd 可以看出来
    if(enable_malloc_hook){
        enable_malloc_hook = 0;
        
        void *p = __libc_malloc(size);

        //这个函数返回是一个地址,可以通过地址看出来是哪一个文件,哪一行,哪个函数
        //而且编译需要加上-g
        void *caller = __builtin_return_address(0);

        //这里做法是创建一个文件
        char buff[128] ={0};
        sprintf(buff,"%p.mem",p);

        FILE *fp = fopen(buff,"w");
        fprintf(fp,"malloc [+%p]-->addr:%p size: %ld\n",caller,p,size);
        fflush(fp);
        // fclose(fp);//有问题
        // printf("malloc [+%p]-->addr:%p size: %ld\n",caller,p,size);
        enable_malloc_hook = 1;
        return p;
    }else{
        return __libc_malloc(size);
    }
    return NULL;
}
void free(void *p){
    if(enable_malloc_hook){
        enable_malloc_hook =0;

        char buff[128] ={0};
        sprintf(buff,"%p.mem",p);
        if(unlink(buff)<0){//文件不存在,该函数表示删除buff文件,文件不存在,就删除不了
            printf("double free:%p\n",p);
        }else{

        }
        __libc_free(p);
        enable_malloc_hook=1;
    }else{
        __libc_free(p);
    }
    
}

版本2

重写malloc设置宏定义

void *malloc_hook(size_t size,const char* file,int line){
    void *p = malloc(size);
//这里做法是创建一个文件
    char buff[128] ={0};
    sprintf(buff,"%p.mem",p);

    FILE *fp = fopen(buff,"w");
    fprintf(fp,"malloc [+%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,"%p.mem",p);
    if(unlink(buff)<0){//文件不存在,该函数表示删除buff文件,文件不存在,就删除不了
        printf("double free:%p,File:%s:%d\n",p,file,line);
        return ;
    }
    free(p);
}
//注意下面的宏不可放在上面函数前,需要调试打开IF就行
#if 0
#define malloc(size)     malloc_hook(size,__FILE__,__LINE__)
#define free(p)      free_hook(p,__FILE__,__LINE__)
#endif

版本3

挂钩子

#include <malloc.h>
typedef void *(*malloc_hook_t)(size_t,const void *caller);
malloc_hook_t malloc_f;
typedef void (*fire_hook_t)(void *p,const void *caller);
fire_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();//将下面malloc还是设置走系统
    void* ptr = malloc(size);
    char buff[128] ={0};
    sprintf(buff,"%p.mem",ptr);

    FILE *fp = fopen(buff,"w");
    fprintf(fp,"malloc [+%p]-->addr:%p size: %ld\n",caller,ptr,size);
    fflush(fp);
    fclose(fp);
    mem_trace();
    return ptr;
}
void *free_hook_f(void *p,const void *caller){
    mem_untrace();
    char buff[128] ={0};
    sprintf(buff,"%p.mem",p);
    if(unlink(buff)<0){//文件不存在,该函数表示删除buff文件,文件不存在,就删除不了
        printf("double free:%p,File:%p\n",p,caller);
        return ;
    }
    free(p);
    mem_trace();
}

//挂钩子
void mem_trace(void){//mtracemalloc会执行
    //保存系统的
    replaced = 1;
    malloc_f = __malloc_hook;
    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;
}

版本4

使用matrc
mtrace开源库。
注意一定要再终端执行:export MALLOC_TRACE=./test.log
不然日志没办法输出

#include <mcheck.h>
void main(){
	mtrace();

    void *p1 = malloc(10);
    void *p2 = malloc(20);

    free(p1);
    muntrace();//版本4 mtrace开源库
}

得出来的test.log,文件可以看到有加减,加的地址对应减的地址 剔除掉,
保留下来的就是内存泄漏的
终端命令:addr2line -f -e (执行文件名字) -a (这里写caller地址)

共享内存

再系统空间里 有一块内存专门做共享内存的
不是在堆里也不是在栈里,在进程的虚拟空间中有一块自己的空间,是用于映射在空一块地方的,就是A进程与B进程操作的共享内存是同一块,映射的是同一块物理内存
fork()函数创建时,子进程继承父进程数据,但是随着时间推移,都有自己的独立思想,就是爸爸与儿子一样,儿子继承老爸的血,但是后天有学习能力

方式1

#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
void *shm_mmap_alloc(int size){
    /*MAP_ANON任何文件*/
    void *addr = mmap(NULL,size,PROT_READ|PROT_WRITE,MAP_ANON|MAP_SHARED,-1/*匿名*/,0);
    if(addr == MAP_FAILED){//映射失败
        return NULL;
    }
    return addr;
}
//释放
int shm_mmap_free(void* addr,int size){
    return munmap(addr,size);
}
int main(){
    //创建共享内存
    char* addr = (char*)shm_mmap_alloc(1024);
    //开进程
    pid_t pid =fork();
    if(pid ==0){
        //子进程
        int i = 0;
        while(i<26){
            addr[i] = 'a'+i++;
            addr[i] = '\0';
            printf("children:%s\n",addr);
            sleep(1);
        }
    }else if(pid>0){
        //父进程
        int i = 0;
        while(i++<26){
            printf("father:%s\n",addr);

            sleep(1);
        }
    }
    //释放
    shm_mmap_free(addr,1024);

    return 0;
}

方式2

#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/fcntl.h>
void *shm_mmap_alloc(int size){
    /*MAP_ANON任何文件*/
    ///dev/zero 就是一个黑洞,不管往里面写多少都是0
    int fd = open("/dev/zero",O_RDWR);
    void *addr = mmap(NULL,size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
    close(fd);
    if(addr == MAP_FAILED){//映射失败
        return NULL;
    }
    return addr;
}
//释放
int shm_mmap_free(void* addr,int size){
    return munmap(addr,size);
}
int main(){
    //创建共享内存
    char* addr = (char*)shm_mmap_alloc(1024);
    //开进程
    pid_t pid =fork();
    if(pid ==0){
        //子进程
        int i = 0;
        while(i<26){
            addr[i] = 'a'+i++;
            addr[i] = '\0';
            printf("children:%s\n",addr);
            sleep(1);
        }
    }else if(pid>0){
        //父进程
        int i = 0;
        while(i++<26){
            printf("father:%s\n",addr);

            sleep(1);
        }
    }
    //释放
    shm_mmap_free(addr,1024);

    return 0;
}

仅供学习,不佞赐教

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老了希望

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值