内存泄露 防止在程序关闭后还有忘记释放的内存

2024-06-18 19:18

本文主要是介绍内存泄露 防止在程序关闭后还有忘记释放的内存,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


主要是解决自己分配的内存忘记释放的问题,自己定义了几个函数取代了malloc,calloc,realloc,free这几个函数,尽量跟原有用法一致。



头文件mypool.h

#ifndef _MYPOOL_H
#define _MYPOOL_H

struct Node
{
struct Node *preNode;//前一个节点
struct Node *nextNode;//后一个节点
void **varAddr;//存储指针变量的地址
int size;
char freed;
};

struct Chain
{
struct Node *first;
struct Node *last;
int size;
};
void InitChain();
struct Node* InitNode(struct Node *pn);
int Push(struct Node *pn);
int RemoveChain(void **id);
int FreeChain();


void* MyMalloc(void **p,int size);
void* MyCalloc(void **p,int nsize,int usize);
void* MyRealloc(void **p,int size);
void MyFree(void **p);
#endif



实现代码:mypool.c



/************************************************************************/

/*这些代码主要是实现对自己分配的内存的管理,主要是为了防止在程序关闭后还有忘记释放的内存;*/

/*这块代码并不涉及对内存区块的分配管理。*/

/* 作者:jackyvan ,Email:jackyyvan@gmail.com */

/************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mypool.h"

static struct Chain chain;//定义一个链表的静态变量


/*初始化链表*/
void InitChain()
{
chain.first=NULL;
chain.last=NULL;
chain.size=0;
}
/*初始化一个链表上的节点*/
struct Node* InitNode(struct Node *pn)
{
pn=malloc(sizeof(struct Node));
if(pn==NULL)
return NULL;
pn->preNode=NULL;
pn->nextNode=NULL;
pn->freed=0;
pn->varAddr=0;
pn->size=0;
return pn;
}
/*加入一个新的内存分配的节点*/
int Push(struct Node *pn)
{
struct Node *last=chain.last;
struct Node *first=chain.first;
if(first==NULL)
{
chain.first=pn;
chain.last=pn;
}
else
{
chain.last->nextNode=pn;
pn->preNode=chain.last;
chain.last=pn;
}
chain.size++;
return 1;
}
/*
从链表中移除一个节点
*/
int RemoveChain(void **id)
{
struct Node *first=chain.first;
struct Node *tp1=NULL,*tp2=NULL;
if(first==NULL)
return 0;
while(first)
{

if((long)first->varAddr==(long)id)
{
tp1=first->preNode;
tp2=first->nextNode;
if(tp1)
{
if(tp2)
{
tp1->nextNode=tp2;
tp2->preNode=tp1;
}
else
{
tp1->nextNode=NULL;
chain.last=tp1;
}
}
else
{
tp2->preNode=NULL;
chain.first=tp2;
}
free(first);
chain.size--;
break;
}
first=first->nextNode;
}
return 1;
}
/*清空链表*/
int FreeChain()
{
struct Node *first=chain.first;
struct Node *tp1=NULL;
while(first)
{
tp1=first->nextNode;
free((void *)*(first->varAddr));
free(first);
first=tp1;
}
chain.first=NULL;
chain.last=NULL;
chain.size=0;
return 1;
}
/*
自定义的malloc,calloc,realloc,free函数
void **p参数 是存储分配内存地址的变量的地址,根据这个地址与分配内存关联,进行管理
*/
void* MyMalloc(void **p,int size)
{
struct Node *pn=NULL;
(*p)=malloc(size);
if(p==NULL)
return NULL;
pn=InitNode(pn);
if(pn==NULL)
return NULL;
pn->varAddr=p;
pn->size=size;
Push(pn);
return (*p);
}
void* MyCalloc(void **p,int nsize,int usize)
{
struct Node *pn=NULL;
(*p)=calloc(nsize,usize);
if(p==NULL)
return NULL;
pn=InitNode(pn);
if(pn==NULL)
return NULL;
pn->varAddr=p;
pn->size=nsize*usize;
Push(pn);
return (*p);
}
void* MyRealloc(void **p,int size)
{
struct Node *pn=NULL;
(*p)=realloc((*p),size);
if(p==NULL)
return NULL;
pn=InitNode(pn);
if(pn==NULL)
return NULL;
pn->varAddr=p;
pn->size=size;
RemoveChain(p);
Push(pn);
return (*p);
}

void MyFree(void **p)
{
if((*p)==NULL)
return;
free((*p));//释放内存
RemoveChain(p);//把相关节点从链表移除
}


int main()
{
char *p=NULL;
char *p2=NULL;
int *p3=NULL;
InitChain();
p=MyCalloc(&p,100,sizeof(char));
strcpy(p,"abcdefgh...");
p2=MyMalloc(&p2,18*sizeof(char));
p3=MyMalloc(&p3,10*sizeof(int));
p3=MyRealloc(&p3,20*sizeof(int));
MyFree(&p2);
FreeChain();
return 0;
}

这篇关于内存泄露 防止在程序关闭后还有忘记释放的内存的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1072879

相关文章

怎样通过分析GC日志来定位Java进程的内存问题

《怎样通过分析GC日志来定位Java进程的内存问题》:本文主要介绍怎样通过分析GC日志来定位Java进程的内存问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、GC 日志基础配置1. 启用详细 GC 日志2. 不同收集器的日志格式二、关键指标与分析维度1.

Java内存分配与JVM参数详解(推荐)

《Java内存分配与JVM参数详解(推荐)》本文详解JVM内存结构与参数调整,涵盖堆分代、元空间、GC选择及优化策略,帮助开发者提升性能、避免内存泄漏,本文给大家介绍Java内存分配与JVM参数详解,... 目录引言JVM内存结构JVM参数概述堆内存分配年轻代与老年代调整堆内存大小调整年轻代与老年代比例元空

SpringBoot+Redis防止接口重复提交问题

《SpringBoot+Redis防止接口重复提交问题》:本文主要介绍SpringBoot+Redis防止接口重复提交问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不... 目录前言实现思路代码示例测试总结前言在项目的使用使用过程中,经常会出现某些操作在短时间内频繁提交。例

C++高效内存池实现减少动态分配开销的解决方案

《C++高效内存池实现减少动态分配开销的解决方案》C++动态内存分配存在系统调用开销、碎片化和锁竞争等性能问题,内存池通过预分配、分块管理和缓存复用解决这些问题,下面就来了解一下... 目录一、C++内存分配的性能挑战二、内存池技术的核心原理三、主流内存池实现:TCMalloc与Jemalloc1. TCM

Redis过期删除机制与内存淘汰策略的解析指南

《Redis过期删除机制与内存淘汰策略的解析指南》在使用Redis构建缓存系统时,很多开发者只设置了EXPIRE但却忽略了背后Redis的过期删除机制与内存淘汰策略,下面小编就来和大家详细介绍一下... 目录1、简述2、Redis http://www.chinasem.cn的过期删除策略(Key Expir

python编写朋克风格的天气查询程序

《python编写朋克风格的天气查询程序》这篇文章主要为大家详细介绍了一个基于Python的桌面应用程序,使用了tkinter库来创建图形用户界面并通过requests库调用Open-MeteoAPI... 目录工具介绍工具使用说明python脚本内容如何运行脚本工具介绍这个天气查询工具是一个基于 Pyt

Ubuntu设置程序开机自启动的操作步骤

《Ubuntu设置程序开机自启动的操作步骤》在部署程序到边缘端时,我们总希望可以通电即启动我们写好的程序,本篇博客用以记录如何在ubuntu开机执行某条命令或者某个可执行程序,需要的朋友可以参考下... 目录1、概述2、图形界面设置3、设置为Systemd服务1、概述测试环境:Ubuntu22.04 带图

Python程序打包exe,单文件和多文件方式

《Python程序打包exe,单文件和多文件方式》:本文主要介绍Python程序打包exe,单文件和多文件方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录python 脚本打成exe文件安装Pyinstaller准备一个ico图标打包方式一(适用于文件较少的程

Python程序的文件头部声明小结

《Python程序的文件头部声明小结》在Python文件的顶部声明编码通常是必须的,尤其是在处理非ASCII字符时,下面就来介绍一下两种头部文件声明,具有一定的参考价值,感兴趣的可以了解一下... 目录一、# coding=utf-8二、#!/usr/bin/env python三、运行Python程序四、

如何关闭Mac的Safari通知? 3招教你关闭Safari浏览器网站通知的技巧

《如何关闭Mac的Safari通知?3招教你关闭Safari浏览器网站通知的技巧》当我们在使用Mac电脑专注做一件事情的时候,总是会被一些消息推送通知所打扰,这时候,我们就希望关闭这些烦人的Mac通... Safari 浏览器的「通知」功能本意是为了方便用户及时获取最新资讯,但很容易被一些网站滥用,导致我们