内存泄漏以及常见的解决方法

  之所以撰写这篇文章是由于前段时间花费了非常大的精力在已经成熟的代码上再去处理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

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

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

相关文章

python爬取网易云音乐飙升榜音乐_python爬取网易云音乐热歌榜实例代码

首先找到要下载的歌曲排行榜的链接&#xff0c;这里用的是&#xff1a;https://music.163.com/discover/toplist?id3778678然后更改你要保存的目录&#xff0c;目录要先建立好文件夹&#xff0c;例如我的是保存在D盘-360下载-网易云热歌榜文件夹内&#xff0c;就可以完成下载。…

java thread 名称_Thread类常用方法之设置线程名称

package com.itheima.demo02.setName;/*设置线程的名称:(了解)1.使用Thread类中的方法setName(名字)void setName(String name) 改变线程名称&#xff0c;使之与参数 name 相同。2.创建一个带参数的构造方法,参数传递线程的名称;调用父类的带参构造方法,把线程名称传递给父类,让…

HDU 1108 最小公倍数

最小公倍数 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 32794 Accepted Submission(s): 18303Problem Description给定两个正整数&#xff0c;计算这两个数的最小公倍数。Input输入包括多组測试数据&#…

Java为xml跟节点添加子节点_如何将xml节点作为第一个子节点插入Java中的另一个xml文档中?...

小编典典如果事实证明我只是为您做功课&#xff0c;我会感到非常恼火。package com.akonizo.examples;import java.io.ByteArrayInputStream;import java.io.StringWriter;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import j…

成员变量和局部变量的区别_Java 变量类型

点击上方“蓝字”带你去看小星星今天主要学习Java变量类型&#xff0c;主要是局部变量、实例变量和类变量(静态变量)。Java语言中&#xff0c;所有的变量在使用前必须声明。声明变量的基本格式如下&#xff1a;type identifier [ value][, identifier [ value] ...] ;格式说明…

java gson序列化_java – Gson多态序列化

使用Gson 2.2.2我正在尝试序列化POJO(行为)的数组列表.我有一个适配器几乎是我在网上看到的副本&#xff1a;public class BehaviorAdapter implements JsonSerializer {private static final String CLASSNAME "CLASSNAME";private static final String INSTANCE …

【云图】如何制作附近实体店的地图?-微信微博支付宝

【云图】如何制作附近实体店的地图&#xff1f;-微信微博支付宝 原文:【云图】如何制作附近实体店的地图&#xff1f;-微信微博支付宝 摘要&#xff1a; 附近连锁店地图与全国连锁店地图&#xff0c;最大的区别就是&#xff1a; 1、附近连锁店地图需要先定位&#xff0c;然后搜…

php curl跨域cookie_PHP curl模拟文件上传(接口请求实现跨域文件中转)

3e2f08c0c11a8416dd107bbfc9159718.jpg客户端代码请求参数参数类型参数说明$urlstringpost提交的服务器url路径$data数组表单数据$files数组表单文件public function curl_custon_postfields($url, array $data array(), array $files array()){$curlfiles array();foreach …

oracle 分页_80分页查询,不止写法

据孔老先生说,茴香豆的茴字有四种写法,那oracle的分页查询又有多少种写法呢?分页查询,其实本质上就是topN查询的变种, 如果把topN的一部分结果集去掉,就变成了分页.topN的基本写法,两层select,第一层先order by,第二层再用rownum:select owner,object_name,object_id,rownum a…

笔记:Hadoop权威指南 第1章 初识Hadoop

大数据处理遇到问题&#xff1a; (1)、磁盘存储容量快速增加&#xff0c;但是访问速度进步不大&#xff1b;用户乐意使用磁盘共享访问。 (2)、硬件故障&#xff0c;可以使用备份解决。 (3)、分布式系统&#xff0c;需要可靠性。 关系数据库与MapReduce比较&#xff1a; (1)、磁…

php switch if,php switch 与 if else 区别

在php中switch是选择&#xff0c;if else也有同理&#xff0c;但是它们肯定是有区别的&#xff0c;那么我们来看看它们两者的区别在哪里呢&#xff0c;下面先看switch case语句吧。switch($id){case 1:return asp/;break;case 2:return phper/;break;case 3:return jsp/;break;…

python读取mat数据是字典形式如何转化为矩阵_mat2json, python读取mat成字典, 保存json...

python程序, 实现matlab的.mat格式转化为dict / json .第一个参数mat_path代表需要转化的mat路径;第二个参数, 如果需要把字典序列化成json, 添加这一参数, 代表json存放位置;返回值: 转化好的字典import osimport jsonimport scipy.io as spioimport pandas as pddef loadmat(…

GitHub上创建组织

4.3. 组织和团队 GitHub 在早期没有专门为组织提供账号&#xff0c;很多企业用户或大型开源组织只好使用普通用户账号作为组织的共享账号来使用。后来&#xff0c;GitHub推出了组织这一新的账号管理模式&#xff0c;满足大型开发团队的需要。 组织账号是不能用来登录的&#xf…

jquery根据value值php,表单php传值后jquery清除表单某项value问题

表单php文件我现在写了一个jquery打算每次提交后清除姓名中的内容代码如下$(function() { $(:input,#recordform) .not(:button, :submit, :reset, :hidden) .val() })请问怎么使用啊 加在哪个都无法实现提交后清除姓名求助&#xff01;回复讨论(解决方案)不知道你的 js 函数 c…

python未将对象引用设置到对象的实例_在Python中使用pingarapi。服务器引发Webfault:对象引用未设置为对象的实例...

大家晚上好。我想说的是&#xff0c;我对wsdl、soap、suds这整件事都很陌生&#xff01;尽可能多地提供信息。wsdl是这个http://api3.pingar.com/PingarAPIService.asmx?WSDL我花了好几个小时试图找出我正在使用的代码有什么问题&#xff0c;但最终还是一无所获。我借用了这里…

php 网站上传大小限制吗,配置PHP程序网站上传文件大小的限制!

PHP程序做的网站&#xff0c;上传文件大小的限制&#xff0c;是在PHP的配置文件中设置的。WORDPRESS网站也是PHP程序&#xff0c;我们会在WordPress里面的很多地方遇到文件上传大小的限制&#xff0c;比如在媒体库里面&#xff0c;上传图片&#xff1b;恢复数据时&#xff0c;上…

python元组元素抓7_Python3基础 tuple 通过拆分元组向元组中加入新的元素

Python : 3.7.0OS : Ubuntu 18.04.1 LTSIDE : PyCharm 2018.2.4Conda : 4.5.11typesetting : Markdowncode"""Author : 行初心Date : 18-9-23Blog : www.cnblogs.com/xingchuxinGitee : gitee.com/zhichengjiu"""def main():new_members (阳明贪…

Hypothesis, 一个很少人会用的Python测试库

在软件开发中&#xff0c;测试是保证代码质量和功能正确性的重要环节。为了提高测试的覆盖率和效率&#xff0c;开发者们创造了许多测试框架和工具。其中 Hypothesis 是一个强大且受欢迎的 Python 测试库&#xff0c;它利用属性基测试的思想&#xff0c;可以自动生成测试数据并…

用户留存 数据统计 php,位运算实现用户留存率

统计留存率之前先弄清一下留存率的概念&#xff0c;百度百科中是这么说的&#xff1a; 用户在某段时间内开始使用应用&#xff0c;经过一段时间后&#xff0c;仍然继续使用应用的被认作是留存&#xff1b;这部分用户占当时新增用户的比例即是留存率&#xff0c;会按照每隔1单位…

php mcrypt取消,php – Mcrypt弃用后如何解密?

我已将我的php版本更新为7.1.我有使用mcrypt加密数据的功能.现在不推荐使用此功能.无论如何我都可以通过回到旧版本的php来解密数据.这是我使用的代码&#xff1a;public function encrypt($plaintext) {$ivSize mcrypt_get_iv_size(self::CIPHER, self::MODE);$iv mcrypt_cr…