内存泄漏问题的请教!

Caballeroo 2009-09-16 04:02:37
一般我们在写代码的时候,可能会用到malloc()申请内存空间,最后会通过free来将该空间进行释放。
但是在操作过程中,一部小心就会造成内存泄漏,

比如: char *buf=NULL;
buf=(char *)malloc(50);
buf="abcdefg" //此时丢掉了原本分配的地址

所以最后free时,将会报错free(): invalid pointer.

有个简单的办法就是每次malloc后先保存该地址,这样上面的代码可改成

char *buf=NULL;
char *tp=NULL;
buf=(char *)malloc(50);
tp=buf;
buf="abcdefg" //此时丢掉了原本分配的地址,

buf=tp;

所以最后free时,就不会报错了。






请问有没有什么更好的方法,来避免这种操作中不经意的内存泄漏,谢谢!
...全文
233 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
sixiangduwu 2011-03-16
  • 打赏
  • 举报
回复
用工具测试
eatsweetpotato 2009-09-19
  • 打赏
  • 举报
回复
要是c++话,就智能指针吧
王兵2019 2009-09-19
  • 打赏
  • 举报
回复
Oh,my god
jackwini 2009-09-19
  • 打赏
  • 举报
回复
char *buf=NULL;
buf=(char *)malloc(50);
buf="abcdefg" //此时丢掉了原本分配的地址

此时可以将 buff的申明改为:

char *const buff = (char *)malloc(50);

这样当编译时, buf="abcdefg"就会报错。可以避免对buff指针的重新赋值
jasonnbfan 2009-09-18
  • 打赏
  • 举报
回复
其他人说的都不对,针对楼主的代码,12楼是唯一正确答案。
memset()是关键。
LightInDark_pan 2009-09-18
  • 打赏
  • 举报
回复
这个没有啥好办法的,得靠你的经验了。可以通过宏的方式来检查内存泄露。其实内存泄露除了malloc/free new/delete外,还有就是系统资源的泄露, 比如fopen,而没有fclose 等。需要良好的编程习惯来解决,出现内存泄露可以使用宏的方式来查找。
yoyo_alex_lw 2009-09-18
  • 打赏
  • 举报
回复
.h 文件


#ifndef CMEMMANAGER_H
#define CMEMMANAGER_H

//内存管理节点,使用单链表来完成内存的管理
//内存分配记录分配的文件名称、行号、时间,这利于内存泄漏查找;
//另外有统一的全部分配内存释放,让应用程序结束时统一释放所有分配的内存;
//考虑到使用全局的单链表(准确说是链堆栈)内存分配与释放需要修改链表结构
//因此,需要考虑多线程问题,内存分配与释放需要提供线程锁
typedef struct mem_node_st
{
void* pData;//实际内存地址
size_t size;//分配大小
long lRef;//引用次数,暂时使用0,1表示是否分配,不做次数使用,可以用来自动内存回收
const char* file;//分配内存的文件名
long line;//分配内存的文件行号
time_t time;//分配内存时间
pthread_t threadid;//线程id
static long nodeCount;//所有分配的结点计数
mem_node_st* pNext;//下一个节点
}Mem_Node;

//头结点
//extern struct Mem_Node* p_gHead;

//生成结点
Mem_Node* iMallocMemNode();
//释放结点及结点数据内存
void iFreeMemNode(Mem_Node* p);

//初始化,生成头结点
int iInit();
//释放整个链表内存
void iFinal();
//生成结点并为结点元素分配内存
void* iMalloc(size_t size,const char* file,long line);
//释放结点元素内存并删除该结点
void iFree(void* pv);

#ifdef DEBUG
#define LM_INIT iInit
#define LM_FINAL iFinal
#define LM_MALLOC(size) iMalloc(size,__FILE__,__LINE__)
#define LM_FREE(pv) iFree(pv)
#else
#define LM_INIT ;
#define LM_FINAL ;
#define LM_MALLOC(size) malloc(size)
#define LM_FREE(pv) free(pv)
#endif //DEBUG


#endif//CMEMMANAGER_H

.cpp文件

// CMemManager.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <time.h>
#include <pthread.h>
#include "CMemManager.h"

#include <memory>
//#include <crtdbg.h>
#include <assert.h>

#define GARBAGE_CHAR 0xCC

pthread_mutex_t g_MemMutex = PTHREAD_MUTEX_INITIALIZER;

void *threadrun(void *arg);

int main(int argc, char* argv[])
{
printf("Hello World!\n");
int r = LM_INIT();
if (!r)
{
return 0;
}

const int threadcount = 50;
pthread_t threadid[threadcount];
for (int i = 0; i < threadcount; ++ i)
{
pthread_create(&threadid[i],NULL,threadrun,NULL);
}

size_t t1 =10,t2 = 100,t3 = 1000;
unsigned char* p1,*p2,*p3;
p1 =(unsigned char*) LM_MALLOC(t1);
if (!p1)
{
goto ERR;
}
LM_FREE(p1);
p2 = (unsigned char*) LM_MALLOC(t2);
if (!p2)
{
goto ERR;
}
LM_FREE(p2);
p3 = (unsigned char*) LM_MALLOC(t3);

ERR:
pthread_mutex_lock(&g_MemMutex);
LM_FINAL();
pthread_mutex_unlock(&g_MemMutex);
return 0;
}


//分配内存管理结点内存
Mem_Node* iMallocMemNode()
{
Mem_Node* p;
p = (Mem_Node*)malloc(sizeof(Mem_Node));
if (!p)
{
return NULL;
}
p->pData = NULL;
p->size = sizeof(Mem_Node);
p->lRef = 0;
p->pNext = NULL;

return p;
}
//释放结点管理的内存
void iFreeMemNode(Mem_Node* p)
{
assert(p);
#ifdef _DEBUG
{memset(p->pData,GARBAGE_CHAR,p->size);}
#endif // _DEBUG
free(p->pData);
free(p);
}
//头结点
Mem_Node* p_gHead = NULL;
long Mem_Node::nodeCount = 0;
int iInit()
{
assert(!p_gHead);
// if (p_gHead)
// {
// iFreeMemNode(p_gHead);
// }
p_gHead = iMallocMemNode();
p_gHead->file = __FILE__;
p_gHead->line = __LINE__;
time(&p_gHead->time);
p_gHead->threadid = pthread_self();
p_gHead->nodeCount ++;

return (p_gHead != NULL);
}

void* iMalloc(size_t size,const char* file,long line)
{
assert(size > 0);
Mem_Node* pNew,*pHeadNext;

pthread_mutex_lock(&g_MemMutex);
pHeadNext = p_gHead->pNext;
pNew = iMallocMemNode();
if (!pNew)
{
pthread_mutex_unlock(&g_MemMutex);
return NULL;
}
pNew->pData = malloc(size);
if(!pNew->pData)
{
free(pNew);
pthread_mutex_unlock(&g_MemMutex);
return NULL;
}
#ifdef _DEBUG
{memset(pNew->pData,GARBAGE_CHAR,size);}
#endif // _DEBUG
pNew->size = size;
pNew->lRef = 1;
pNew->file = file;
pNew->line = line;
time(&pNew->time);
pNew->threadid = pthread_self();

p_gHead->pNext = pNew;
pNew->pNext = pHeadNext;
p_gHead->nodeCount ++;
pthread_mutex_unlock(&g_MemMutex);
return pNew->pData;
}
void iFree(void* pv)
{
assert(pv);
pthread_mutex_lock(&g_MemMutex);
//unsigned char* d = (unsigned char*)pv;
Mem_Node* prevT = p_gHead;
Mem_Node* t = prevT->pNext;
while (t)
{
//if (!memcmp(t->pData,d,t->size))
if (pv == t->pData)
{
break;
}
else
{
prevT->pNext = t;
t = t->pNext;
}
}
assert(t);
prevT->pNext = t->pNext;
iFreeMemNode(t);
p_gHead->nodeCount --;
pthread_mutex_unlock(&g_MemMutex);
return;
}
void iFinal()
{
Mem_Node* next ;
while(p_gHead)
{
next = p_gHead->pNext;
iFreeMemNode(p_gHead);
p_gHead = next;
}
p_gHead = NULL;
}



int g_size = 100;
void *threadrun(void *arg)
{
LM_MALLOC(g_size);
int i = p_gHead->nodeCount;
printf("threadcount =%d , threadid ====%#x\n",i,pthread_self());
g_size += 20;
//pthread_exit(NULL);
return NULL;
}
yoyo_alex_lw 2009-09-18
  • 打赏
  • 举报
回复
使用assert类似的策略,在debug时写个封装malloc,free的函数,release时使用原生的malloc,free.
debug时,使用一个结构保存malloc时内存分配的file,line,size,address,time等,用单链表把这些节点链接起来,free时删除该链表中对应的节点并释放内存。这样在应用程序最后退出处,打印该单链表的节点数据,分析这些数据,就能发现那些是没有释放的内存(一般有节点数据,就表示有泄漏)。这样在debug时能够检测出这些内存泄露问题。由于记录了内存分配的文件名,行号就很容易找出问题了。这样讲内存泄露在debug版本中都解决掉。
猪翼天翔 2009-09-18
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 jasonnbfan 的回复:]
其他人说的都不对,针对楼主的代码,12楼是唯一正确答案。
memset()是关键。
[/Quote]
LZ的问题是将“指向动态分配的内存”的buf指针指向了常字符串"abcdefg",从而造成之前动态分配的内存块没法释放,memcpy才是关键吧
dongpy 2009-09-18
  • 打赏
  • 举报
回复
如果是局部范围的动态内存申请释放,可以考虑垃圾回收器,分配使用后统一释放。
churenxh 2009-09-17
  • 打赏
  • 举报
回复
动态申请基本的格式:
PBYTE PageNum = new BYTE [44]; //一个页的字节大小
if (PageNum==NULL)
{
AfxMessageBox(_T("内存申请失败!"));
return ;
}

.................
if (PageNum!= NULL)
{
delete[] PageNum;
PageNum = NULL;
}
wissup 2009-09-17
  • 打赏
  • 举报
回复
没有什么特别好方法的,你就只能记住malloc之后,就一定要free,这就是最好的习惯。

因为就算是宏帮你再绑定了一次,你也要去调用,那还不如你直接调用free。

当然如果用宏去避免其他的内存管理错误还是可以实现的。

但这个努力将是比较大的。
pustian 2009-09-17
  • 打赏
  • 举报
回复
没有什么特别好方法的,你就只能记住malloc之后,就一定要free,这就是最好的习惯。
我觉得楼主
char *buf=NULL;
buf=(char *)malloc(50);
buf="abcdefg" //此时丢掉了原本分配的地址
最好自己管理内存,确认写到分配的内存里
buf=(char *)malloc(50);
memset(buf,0x00,50);
char tmp[]="abcdef";
memcpy(buf,tmp,sizeof(char)*(strlen(tmp)+1))
最后free时就不会有问题
Caballeroo 2009-09-16
  • 打赏
  • 举报
回复
jamesf1982 哥哥,来说两句!
ChRedfield 2009-09-16
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 caballeroo 的回复:]
引用 4 楼 jamesf1982 的回复:
这个还是得自己小心点,我用的方法是将所有动态申请内存的变量放在一个全局结构中,这样可以较好的识别出该指针是否动态内存。

另外malloc之前先检查指针是否为NULL,free时记得将指针指向NULL



这个方法不错,能不能具体点介绍下下!
[/Quote]

等待中。
CPFeng0124 2009-09-16
  • 打赏
  • 举报
回复
标准c定义了4种动态分配函数,它们可以用于所有编译程序,calloc(),malloc(),free(),realloc()!用malloc()函数时,返回一个指针,指向从堆中分配的size字节内存区,如果堆中内存不能满足分配请求时,malloc()返回一个空指针!使用之前,必须核实返回的指针不能为空,否则将导致系统瘫痪
Caballeroo 2009-09-16
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 jamesf1982 的回复:]
这个还是得自己小心点,我用的方法是将所有动态申请内存的变量放在一个全局结构中,这样可以较好的识别出该指针是否动态内存。

另外malloc之前先检查指针是否为NULL,free时记得将指针指向NULL
[/Quote]


这个方法不错,能不能具体点介绍下下!
Caballeroo 2009-09-16
  • 打赏
  • 举报
回复
come on!
james_hw 2009-09-16
  • 打赏
  • 举报
回复
这个还是得自己小心点,我用的方法是将所有动态申请内存的变量放在一个全局结构中,这样可以较好的识别出该指针是否动态内存。

另外malloc之前先检查指针是否为NULL,free时记得将指针指向NULL
  • 打赏
  • 举报
回复
仔细的检查你的代码
好的编程习惯来避免
加载更多回复(2)

69,377

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧