之所以撰写这篇文章是由于前段时间花费了非常大的精力在已经成熟的代码上再去处理memory leak问题。写此的目的是希望我们应该养成良好的编码习惯,尽可能的避免这种问题,由于当你对着一大片的代码再去处理此类的问题,此时无疑添加了解决的成本和难度。准确的说属于补救措施了。
1. 什么是内存泄漏(memory leak)?
 指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。 

A memory leak is a particular type of unintentional memory consumption by a computer program where the program fails to release memory when no longer needed. This condition is normally the result of a bug in a program that prevents it from freeing up memory that it no longer needs.This term has the potential to be confusing, since memory is not physically lost from the computer. Rather, memory is allocated to a program, and that program subsequently loses the ability to access it due to program logic flaws.

2. 对于C和C++这样的没有Garbage Collection 的语言来讲,我们主要关注两种类型的内存泄漏:

堆内存泄漏(Heap leak)。对内存指的是程序执行中依据须要分配通过malloc,realloc new等从堆中分配的一块内存,再是完毕后必须通过调用相应的 free或者delete 删掉。假设程序的设计的错误导致这部分内存没有被释放,那么此后这块内存将不会被使用,就会产生Heap Leak.

  系统资源泄露(Resource Leak).主要指程序使用系统分配的资源比方 Bitmap,handle ,SOCKET等没有使用对应的函数释放掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定。  
3. 怎样解决内存泄露?
内存泄露的问题其困难在于1.编译器不能发现这些问题。2.执行时才干捕获到这些错误,这些错误没有明显的症状,时隐时现。3.对于手机等终端开发用户来说,尤为困难。以下从三个方面来解决内存泄露:
第一,良好的编码习惯,尽量在涉及内存的程序段,检測出内存泄露。当程式稳定之后,在来检測内存泄露时,无疑添加了排除的困难和复杂度。
使用了内存分配的函数,要记得要使用其想用的函数释放掉,一旦使用完成。
Heap memory:
malloc\realloc ------  free
new \new[] ----------  delete \delete[]
GlobalAlloc------------GlobalFree 
要特别注意数组对象的内存泄漏
     MyPointEX *pointArray =new MyPointEX [100];
      其删除形式为:
     delete []pointArray 
Resource Leak :对于系统资源使用之前要细致看起用法,防止错误使用或者忘记释放掉系统资源。
我们看MSDN上一个创建字体的样例:
 RECT rect;
HBRUSH hBrush;
FONT hFont;
hdc = BeginPaint(hWnd, &ps);
 hFont = reateFont(48,0,0,0,FW_DONTCARE,FALSE,TRUE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS,CLEARTYPE_QUALITY, VARIABLE_PITCH,TEXT("Impact"));
SelectObject(hdc, hFont); 
SetRect(&rect, 100,100,700,200);
SetTextColor(hdc, RGB(255,0,0));

DrawText(hdc, TEXT("Drawing Text with Impact"), -1,&rect, DT_NOCLIP);

DeleteObject(hFont);  
 EndPaint(hWnd, &ps);
假设使用完毕时候忘记释放字体,就造成了资源泄漏。 
   对于基于引用计数的系统对象尤其要注意,由于仅仅有其引用计数为0时,该对象才干正确被删除。而其使用过程中有其生成的新的系统资源,使用完成后,假设没有及时删除,都会影响其引用计数。
 IDNS *m_pDns//define a DNS object.
   If(NULL == m_pDns)
{  
   IEnv_CreateInstance (m_pEnv,AEECLSID_DNS,(void **) (&m_pDns))

}

 If(m_pDns)
{

Char szbuff[256];

IDNS_AddQuestions(M_pDns,AEEDNSTYPE_A,ADDDNSCLASS_IN,szbuff);

IDNS_Start(m_pDns,this);

const AEEDNSResponse * pDnsResponse = NULL;

IDNS_GetResponse(pMe->m_pDns, &pDnsResponse);

…………………………………………………………

…………………………………………………………..

………………………………………………………..

}

DNS_Release(pMe->m_pDns);//当程序执行到此时,其返回值不是0,是1,其含义是程序已经产生内存泄露了,系统已经有一个由DNS所产生的内核对象没有释放,而当这段代码多次执行之后,内存泄露将不断添加……..

m_pDns=NULL;

}

看起来非常不直观,细致分析就会发现,对象pDnsResponse是从m_pDns产生新的object,所以m_pDns的引用计数会添加,因此在使用完pDnsResponse,应该release 该对象使其引用计数恢复正常。
 
对于资源,也可使用RAII,RAII(Resource acquisition is initialization)资源获取即初始化,它是一项非常easy的技术,利用C++对象生命周期的概念来控制程序的资源,比如内存,文件句柄,网络连接以及审计追踪(audit trail)等.RAII的基本技术原理非常easy.若希望保持对某个重要资源的跟踪,那么创建一个对象,并将资源的生命周期和对象的生命周期相关联.如此一来,就能够利用C++复杂老练的对象管理设施来管理资源.(有待完好) 
例2: 
Struct ITypeface *pTypeface;
if (pTypeface)
{
IANY_CreateInstance(g_pApplet->m_pIShell,AEECLSID_BTFETypeface,void**)& Typeface);
} 
接下来我们就能够从这个接口上面创建字体,比方
IHFont **pihf=NULL;
   ITypeface_NewFontFromFile(ITypeface,……,&pihf).
   ITypeface_NewFontFrommemory(ITypeface,……..,&pihf)
   ITypeface_NewFontFromClassID(IType,……,&pihf)
 
   可是要切记,这些字体在使用完毕后一定要release掉,否则最后 iTypeface的引用计数就是你最后没有删除掉的字体的个数。 
第二,重载  new 和 delete。这也是大家编码过程中常用的方法。
以下给出简单的sample来说明。
memchecker.h
structMemIns
{
    void * pMem;
    int m_nSize;
    char m_szFileName[256];
    int m_nLine;
    MemIns * pNext;
};
classMemManager
{
public:
    MemManager();
    ~MemManager();
private:
    MemIns *m_pMemInsHead;
    int m_nTotal;
public:
    static MemManager* GetInstance();
    void Append(MemIns *pMemIns);
    void Remove(void *ptr);
    void Dump(); 
 
};
void *operatornew(size_tsize,constchar*szFile, int nLine);
void operatordelete(void*ptr,constchar*szFile, int nLine);
 void operatordelete(void*ptr);
void*operatornew[] (size_tsize,constchar*szFile,int nLine);
void operatordelete[](void*ptr,constchar*szFile, int nLine);
void operatordelete[](void *ptr);
 
memechecker.cpp
#include"Memchecher.h"
#include<stdio.h>
#include<malloc.h>
#include<string.h>
 
MemManager::MemManager()
{
    m_pMemInsHead=NULL;
    m_nTotal=NULL;
}
MemManager::~MemManager()
{
 
}
voidMemManager::Append(MemIns *pMemIns)
{
    pMemIns->pNext=m_pMemInsHead;
    m_pMemInsHead = pMemIns;
    m_nTotal+= m_pMemInsHead->m_nSize;
 
}
voidMemManager::Remove(void *ptr)
{
    MemIns * pCur = m_pMemInsHead;
    MemIns * pPrev = NULL;
    while(pCur)
    {
        if(pCur->pMem ==ptr)
        {
           if(pPrev)
            {
               pPrev->pNext =pCur->pNext;
            }
           else
            {
               m_pMemInsHead =pCur->pNext;
            }
           m_nTotal-=pCur->m_nSize;
           free(pCur);
           break;
        }
        pPrev = pCur;
        pCur = pCur->pNext;
    }
 
}
voidMemManager::Dump()
{
    MemIns * pp = m_pMemInsHead;
    while(pp)
    {
        printf( "File is %s\n", pp->m_szFileName );
        printf( "Size is %d\n", pp->m_nSize );
        printf( "Line is %d\n", pp->m_nLine );
        pp = pp->pNext;
    }
 
}
 
voidPutEntry(void *ptr,intsize,constchar*szFile, int nLine)
{
    MemIns * p = (MemIns *)(malloc(sizeof(MemIns)));
    if(p)
    {
        strcpy(p->m_szFileName,szFile);
        p->m_nLine = nLine;
        p->pMem = ptr;
        p->m_nSize = size;
        MemManager::GetInstance()->Append(p);
    }
}
voidRemoveEntry(void *ptr)
{
    MemManager::GetInstance()->Remove(ptr);
}
 
 
void *operatornew(size_tsize,constchar*szFile, int nLine)
{
    void * ptr = malloc(size);
    PutEntry(ptr,size,szFile,nLine);
    return ptr;
}
voidoperatordelete(void *ptr)
{
    RemoveEntry(ptr);
    free(ptr);
}
void operatordelete(void*ptr,constchar * file, intline)
{
    RemoveEntry(ptr);
    free(ptr);
}
 
void*operatornew[] (size_tsize,constchar* szFile,intnLine)
{
    void * ptr = malloc(size);
    PutEntry(ptr,size,szFile,nLine);
    return ptr;
}
 
void operatordelete[](void *ptr)
{
    RemoveEntry(ptr);
    free(ptr);
}
 
void operatordelete[](void*ptr,constchar*szFile,intnLine)

{

转载于:https://www.cnblogs.com/mengfanrong/p/4198664.html

内存泄漏以及常见的解决方法相关推荐

  1. 内存泄漏的原因及解决方法

    内存泄漏就是内存中的变量没有回收,一直存在与内存中,造成内存的浪费的行为.常见的内存泄漏有以下5种 1. 意外的全局变量 2. 计时器和回调函数timers 3. DOM泄漏 4. js闭包 5. c ...

  2. MFC多线程内存泄漏问题amp;解决方法

    MFC多线程内存泄漏问题&解决方法 参考文章: (1)MFC多线程内存泄漏问题&解决方法 (2)https://www.cnblogs.com/lcchuguo/p/5224576.h ...

  3. iOS 内存泄漏的常见场景

    内存泄漏的常见场景 CF类型内存 注意以create,copy作为关键字的函数都是需要释放内存的,注意配对使用.比如:CGColorCreate<-->CGColorRelease MRC ...

  4. 鸿合一体机触屏没反应怎么办_电脑一体机触摸屏没反应 触摸屏电脑一体机常见故障解决方法...

    触摸屏电脑一体机常见故障解决方法 1.触摸屏不准 一台五线电阻触摸屏,用手指触摸显示器屏幕的部位不能正常地完成对应的操作. [故障分析处理] 这种现象可能是电阻屏的校对有问题. 在下列情况下可运行屏幕 ...

  5. jack server 常见错误解决方法

    jack 服务常见错误解决方法 当你编译Android时,你不需要修改任何内容. Jack是Andriod M的默认编译工具.只需使用标准的makefile命令执行即可.当第一次执行jack时,它会在 ...

  6. jack 服务常见错误解决方法

    jack 服务常见错误解决方法 当你编译Android时,你不需要修改任何内容. Jack是Andriod M的默认编译工具.只需使用标准的makefile命令执行即可.当第一次执行jack时,它会在 ...

  7. 台式计算机无法启动不了,台式机和笔记本电脑主机启动不了常见原因解决方法...

    电脑最常见的问题恐怕就是电脑主机启动不了的问题了,而面对这种问题我们能做的又是什么呢,当然是想办法找到原因并解决它.以下是自己在日常处理电脑问题故障中积累的一些经验希望可以帮助到大家. 1.主板内存的 ...

  8. 打游戏计算机内存不足,电脑玩cf游戏内存不足的两种解决方法

    电脑出现内存不足是一种较为常见的电脑故障,常见于运行大型游戏的时候发生此类故障.最近,一些小伙伴说电脑玩cf游戏内存不足,怎么办?cf穿越火线是一款第一人称射击游戏的网络游戏,如果想要运行cf游戏,不 ...

  9. jack server 常见错误解决方法【转】

    本文转载自:https://blog.csdn.net/qq_27061049/article/details/70156200 jack 服务常见错误解决方法 当你编译Android时,你不需要修改 ...

最新文章

  1. Android 使用XmlPullParser解析xml
  2. js,在字符串中,查找某个字符的位置
  3. Android 8.0学习(31)---Android 8.0 中的 ART 功能改进
  4. 【Kafka】kafka Failed to acquire lock on file .lock in /data/kafak-logs a kafka instance
  5. 360浏览器打不开qq空间_360浏览器打不开? 60浏览器打不开网页的处理方法(图文)...
  6. cocos JS 定时器
  7. SCCM 2012系列2 服务器准备下
  8. extjs中rowEditing动态编辑
  9. 仿Hex-Editor,实现简单地二进制文件查看器JHexer
  10. 超简单APP图标制作
  11. 计算机二进制乘法运算(原码,补码)
  12. office2007设置默认粘贴为选择性粘贴
  13. PS画直线虚线及图形虚线
  14. Windows10虚拟机安装和使用教程
  15. linux ohmyzsh shell主题包以及修改shell命令
  16. 玩机搞机---小米机型格机 檫除分区后修复nv损坏问题的硬件类修复步骤解析
  17. C#连接mysql数据库实现登陆注册界面【小白教程】
  18. 三星 android 4.4.4,我的手机是三星4.4.4安卓系统,怎么升级到6.1版本
  19. 趋势科技2014年暑期实习生笔试题
  20. FE节点挂掉且重启报错sleepycat.je.LockTimeoutException: (JE 7.3.7) Lock expired

热门文章

  1. c++ 访问控制与封装
  2. (全排列)Smallest Difference (poj2718)
  3. linux分区后盘符找不到,为什么我的磁盘不见了,怎么找回来啊?
  4. c语言高斯白序列x,C语言程序设计程设计指导书(晓庄).doc
  5. python随机函数笔记_Python笔记__random
  6. java调用 restapi 乱码_Java HttpURLConnection模拟请求Rest接口解决中文乱码问题
  7. android radiogroup 获取点击位置_屏幕连点器,解放双手[Android]
  8. 想推翻JAVA的统治? 呵洗洗睡吧
  9. 大学计算机一级b笔记,全国计算机等级一级B Excel考试整理笔记
  10. linux安装gcc运行时库,Linux安装gcc-6.1.0