最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

c++ 排查內(nèi)存泄漏的妙招

 更新時(shí)間:2021年03月08日 09:45:28   作者:源之緣  
這篇文章主要介紹了c++ 如何用輔助類(lèi)排查內(nèi)存泄漏,幫助大家更好的理解和學(xué)習(xí)使用c++,感興趣的朋友可以了解下

前言

對(duì)于c++而言,如何查找內(nèi)存泄漏是程序員亙古不變的話題;解決之道可謂花樣繁多。因?yàn)樽罱玫絈T寫(xiě)程序,擺在我面前的第一個(gè)重要問(wèn)題是內(nèi)存防泄漏。如果能找到一個(gè)簡(jiǎn)單而行之有效的方法,對(duì)后續(xù)開(kāi)發(fā)大有裨益。久思終得訣竅,本文就詳細(xì)介紹我對(duì)此問(wèn)題的應(yīng)對(duì)之策。(文末符完整代碼)

如何判斷內(nèi)存有泄漏

  內(nèi)存分配和釋放對(duì)應(yīng)的操作是new、delete。如何判斷內(nèi)存是否釋放干凈?其實(shí)判斷起來(lái)非常簡(jiǎn)單:一個(gè)獨(dú)立的模塊整個(gè)生存周期內(nèi)new的個(gè)數(shù)和delete的個(gè)數(shù)相等。用偽代碼標(biāo)示如下:

int newCount = 0;
 int deleteCount = 0;

 //new 操作時(shí)
 new class();
 newCount++;

 //delete 操作時(shí)
 delete* objPtr;
 deleteCount++;

 //模塊結(jié)束時(shí)
 if(newCount != deleteCount)
 {
 內(nèi)存有泄漏
 }

如果對(duì)所有的new和delete操作,加上如上幾行代碼,就能發(fā)現(xiàn)是否有內(nèi)存泄漏問(wèn)題。如果采用上面方法解決問(wèn)題,手段太low了。

我們的方法有如下特點(diǎn):

1 使用起來(lái)超級(jí)簡(jiǎn)單,不增加開(kāi)發(fā)難度。

2 發(fā)生內(nèi)存泄漏時(shí),能定位到具體是哪個(gè)類(lèi)。

托管new delete 操作符

  要跟蹤所有的new、delete操作,最簡(jiǎn)單的辦法就是托管new、delete。不直接調(diào)用系統(tǒng)的操作符,而是用我們自己寫(xiě)的函數(shù)處理。在我們的函數(shù)內(nèi)部,則別有洞天; 對(duì)new和delete的跟蹤和記錄就為我所欲也。托管new和delete需用到模板函數(shù),代碼如下:

class MemManage
{
 //單實(shí)例模式
private:
 static MemManage* _instance_ptr;
public:
 static MemManage* instance()
 {
 if (_instance_ptr == nullptr)
 {
  _instance_ptr = new MemManage();
 }
 return _instance_ptr;
 }

public:
 MemManage();

 //new操作 構(gòu)造函數(shù)沒(méi)有參數(shù)
 template <typename T>
 T* New()
 {
 ShowOperationMessage<T>(true);
 return new T();
 };

 //new操作 構(gòu)造函數(shù)有1個(gè)參數(shù)
 template <typename T, typename TParam1>
 T* New(TParam1 param)
 {
 ShowOperationMessage<T>(true);
 return new T(param);
 };

 //new操作 構(gòu)造函數(shù)有2個(gè)參數(shù)
 template <typename T, typename TParam1, typename TParam2>
 T* New(TParam1 param1, TParam2 param2)
 {
 ShowOperationMessage<T>(true);
 return new T(param1, param2);
 };

 //delete 操作
 template <typename T>
 void Delete(T t)
 {
 if (t == nullptr)
  return;

 ShowOperationMessage<T>(false);
 delete t;
 };

 //記錄new delete
 template <typename T>
 void ShowOperationMessage(bool isNew)
 {
 //操作符對(duì)應(yīng)的類(lèi)名稱(chēng)
 const type_info& nInfo = typeid(T);
 QString className = nInfo.name();

 if (isNew)
 {
  _newCount++;
 }
 else
 {
  _deleteCount++;
 }

 if (!_showDetailMessage)
 {
  return;
 }

 if (isNew)
 {
  qDebug() << "*New" << className << ":" << _newCount << ":" << _deleteCount;
 }
 else
 {
  qDebug() << "Delete" << className << ":" << _newCount << ":" << _deleteCount;
 }
 }
}

如何使用輔助類(lèi)

   使用起來(lái)很簡(jiǎn)單,示例代碼如下:

//*****new和delete使用偽代碼

//new操作,需根據(jù)構(gòu)造函數(shù)的參數(shù)個(gè)數(shù)調(diào)用對(duì)應(yīng)的函數(shù)
//構(gòu)造函數(shù) 沒(méi)有參數(shù)
QFile* file = MemManage::instance()->New<QFile>();

//構(gòu)造函數(shù) 有1個(gè)參數(shù)
QFile* file = MemManage::instance()->New<QFile, QString>("filename");

//構(gòu)造函數(shù) 有2個(gè)參數(shù)
QFile* file = MemManage::instance()->New<QFile, QString,bool>("filename",true);

//delete 只有一種形式
MemManage::instance()->Delete(file);

 一個(gè)模塊調(diào)用周期結(jié)束 調(diào)用下列代碼,查看是否有內(nèi)存泄漏:

void ShowNewDelete(bool isShowDetail)
 {
 int leftNew = _newCount - _deleteCount;
 qDebug() << "***********************";
 qDebug() << "total New:" << _newCount << " Delete:" << _deleteCount << " leftNew:" << leftNew;
 }

 MemManage::instance()->ShowNewDelete(true);
 //debug輸出如下,如果leftNew為0,則沒(méi)內(nèi)存泄漏
 total New : 166 Delete : 6 leftNew : 160

進(jìn)一步定位內(nèi)存泄漏問(wèn)題

  通過(guò)判斷new和delete的個(gè)數(shù)是否相等,只是知道了是否有內(nèi)存泄漏;進(jìn)一步定位問(wèn)題,才能方便我們解決問(wèn)題。如果能定位到操作哪一個(gè)類(lèi)時(shí),發(fā)生了內(nèi)存泄漏,則問(wèn)題范圍就大大縮小。我們可以按類(lèi)名,記錄new和delete操作個(gè)數(shù),c++獲取類(lèi)名函數(shù)如下:

const type_info &nInfo = typeid(T);
QString className = nInfo.name();

建立一個(gè)map表,記錄類(lèi)名對(duì)應(yīng)的操作信息:

//每個(gè)類(lèi) 統(tǒng)計(jì)的信息
class MemObjInfo
{
public:
 int NewCount = 0;
 int DeletCount = 0;
 QString ClassName;
};

//map對(duì)照表
QMap<QString, MemObjInfo*> _mapMemObjCount;

//按類(lèi)名統(tǒng)計(jì)
void AddCount(QString& className, bool isNew)
{
 QMap<QString, MemObjInfo*>::ConstIterator i = _mapMemObjCount.find(className);
 if (i == _mapMemObjCount.constEnd())
 {
 MemObjInfo* info = new MemObjInfo();
 info->ClassName = className;
 if (isNew)
 {
  info->NewCount++;
 }
 else
 {
  info->DeletCount++;
 }
 _mapMemObjCount.insert(className, info);
 }
 else
 {
 MemObjInfo* info = i.value();
 if (isNew)
 {
  info->NewCount++;
 }
 else
 {
  info->DeletCount++;
 }
 }
}

如果有內(nèi)存泄漏 則會(huì)輸出如下信息:

如上圖,對(duì)5個(gè)類(lèi)的操作發(fā)送了內(nèi)存泄漏。比如我們知道了類(lèi)OfdDocumentPageAttr發(fā)生內(nèi)存泄漏,就很容易定位問(wèn)題了。

輔助類(lèi)完整代碼:

#ifndef MEMMANAGE_H
#define MEMMANAGE_H

#include <QDebug>
#include <QList>
#include <QMutex>

class LockRealse
{
public:
 LockRealse(QMutex* mutex)
 {
 _mutex = mutex;
 _mutex->lock();
 }

 ~LockRealse()
 {
 _mutex->unlock();
 }

private:
 QMutex* _mutex;
};

class MemObjInfo
{
public:
 int NewCount = 0;
 int DeletCount = 0;
 QString ClassName;
};


class MemManage
{
private:
 static MemManage* _instance_ptr;
public:
 static MemManage* instance()
 {
 if(_instance_ptr==nullptr)
 {
  _instance_ptr = new MemManage();
 }
 return _instance_ptr;
 }

public:
 MemManage()
 {
 _threadMutex = new QMutex();
 _newCount = 0;
 _deleteCount = 0;
 }

 template <typename T>
 T* New()
 {
 ShowOperationMessage<T>(true);
 return new T();
 };

 template <typename T,typename TParam1>
 T* New(TParam1 param)
 {
 ShowOperationMessage<T>(true);
 return new T(param);
 };

 template <typename T,typename TParam1,typename TParam2>
 T* New(TParam1 param1,TParam2 param2)
 {
 ShowOperationMessage<T>(true);
 return new T(param1,param2);
 };

 template <typename T>
 void Delete(T t)
 {
 if(t == nullptr)
  return;

 ShowOperationMessage<T>(false);
 delete t;
 };

 void ShowNewDelete(bool isShowDetail)
 {
 int leftNew = _newCount-_deleteCount;
 qDebug()<<"***********************";
 qDebug()<<"total New:"<<_newCount<<" Delete:"<<_deleteCount<<" leftNew:"<<leftNew;

 if(isShowDetail)
 {
  ShowNewDeleteDetail(false);
 }
 }

 void SetShowDetail(bool enable)
 {
 _showDetailMessage = enable;
 }

 template <typename T>
 void clearAndDelete(QList<T>& list)
 {
 foreach(T item ,list)
 {
  // Delete(item);
 }

 list.clear();
 };

private:
 template <typename T>
 void ShowOperationMessage(bool isNew)
 {
 LockRealse lock(_threadMutex);
 const type_info &nInfo = typeid(T);
 QString className = nInfo.name();
 className=TrimClassName(className);
 AddCount(className,isNew);

 if(isNew)
 {
  _newCount++;
 }
 else
 {
  _deleteCount++;
 }

 if(!_showDetailMessage)
 {
  return ;
 }

 if(isNew)
 {
  qDebug()<<"*New"<<className<<":"<<_newCount<<":"<<_deleteCount;
 }
 else
 {
  qDebug()<<"Delete"<<className<<":"<<_newCount<<":"<<_deleteCount;
 }
 }

 void AddCount(QString& className,bool isNew)
 {
 QMap<QString,MemObjInfo*>::ConstIterator i = _mapMemObjCount.find(className);
 if(i == _mapMemObjCount.constEnd())
 {
  MemObjInfo* info = new MemObjInfo();
  info->ClassName = className;
  if(isNew)
  {
  info->NewCount++;
  }
  else
  {
  info->DeletCount++;
  }
  _mapMemObjCount.insert(className,info);
 }
 else
 {
  MemObjInfo* info = i.value();
  if(isNew)
  {
  info->NewCount++;
  }
  else
  {
  info->DeletCount++;
  }
 }
 }

 void ShowNewDeleteDetail(bool isShowAll)
 {
 QMap<QString,MemObjInfo*>::ConstIterator i = _mapMemObjCount.cbegin();
 for(;i!=_mapMemObjCount.cend();i++)
 {
  MemObjInfo *info = i.value();
  int leftNew =info->NewCount-info->DeletCount ;
  if(leftNew!=0)
  {
  qDebug()<<"*** obj "<<info->ClassName<<" New:"<<info->NewCount
   <<" Delete:"<<info->DeletCount
   <<" Diff:"<<leftNew;
  }
  else
  {
  if(isShowAll)
  {
   qDebug()<<"obj "<<info->ClassName<<" New:"<<info->NewCount
    <<" Delete:"<<info->DeletCount
    <<" Diff:"<<leftNew;
  }
  }
 }
 }

 QString TrimClassName(QString& className)
 {
 int n= className.lastIndexOf(" *");
 if(n<0)
  return className.trimmed();

 return className.mid(0,n).trimmed();
 }

private:
 QMutex *_threadMutex;
 int _newCount;
 int _deleteCount;
 bool _showDetailMessage =false;

 QMap<QString,MemObjInfo*> _mapMemObjCount;
};


#endif // MEMMANAGE_H

后記 

解決內(nèi)存泄漏的方法很多。本文介紹了一種行之有效的方法。開(kāi)發(fā)一個(gè)新項(xiàng)目前,就需確定如何跟蹤定位內(nèi)存泄漏,發(fā)現(xiàn)問(wèn)題越早解決起來(lái)越簡(jiǎn)單。程序開(kāi)發(fā)是循序漸進(jìn)的過(guò)程,一個(gè)功能模塊開(kāi)發(fā)完成后,需及早確定是否有內(nèi)存泄漏。防微杜漸,步步為營(yíng),方能產(chǎn)出高質(zhì)量的產(chǎn)品。

以上就是c++ 防止內(nèi)存泄漏的妙招的詳細(xì)內(nèi)容,更多關(guān)于c++ 防止內(nèi)存泄漏的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C語(yǔ)言詳細(xì)講解while語(yǔ)句的用法

    C語(yǔ)言詳細(xì)講解while語(yǔ)句的用法

    c語(yǔ)言while語(yǔ)句的使用語(yǔ)法如“while(condition)?{statement(s);}”,該語(yǔ)句可以是單個(gè)語(yǔ)句,也可以是一個(gè)語(yǔ)句塊,其條件可以是任意表達(dá)式,true是任意非零值,當(dāng)條件為真時(shí),循環(huán)進(jìn)行迭代
    2022-05-05
  • 深入理解卡特蘭數(shù)及其應(yīng)用

    深入理解卡特蘭數(shù)及其應(yīng)用

    本篇文章是對(duì)卡特蘭數(shù)及其應(yīng)用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C++中棧結(jié)構(gòu)建立與操作詳細(xì)解析

    C++中棧結(jié)構(gòu)建立與操作詳細(xì)解析

    我們可以把棧理解成一個(gè)大倉(cāng)庫(kù),放在倉(cāng)庫(kù)門(mén)口(棧頂)的貨物會(huì)優(yōu)先被取出,然后再取出里面的貨物。而從數(shù)據(jù)的邏輯結(jié)構(gòu)來(lái)看,棧結(jié)構(gòu)起始就是一種線性結(jié)構(gòu)
    2013-10-10
  • C++深入刨析優(yōu)先級(jí)隊(duì)列priority_queue的使用

    C++深入刨析優(yōu)先級(jí)隊(duì)列priority_queue的使用

    最近我學(xué)習(xí)了C++中的STL庫(kù)中的優(yōu)先級(jí)隊(duì)列(priority_queue)容器適配器,對(duì)于優(yōu)先級(jí)隊(duì)列,我們不僅要會(huì)使用常用的函數(shù)接口,我們還有明白這些接口在其底層是如何實(shí)現(xiàn)的
    2022-08-08
  • 基于C++11實(shí)現(xiàn)手寫(xiě)線程池的示例代碼

    基于C++11實(shí)現(xiàn)手寫(xiě)線程池的示例代碼

    在實(shí)際的項(xiàng)目中,使用線程池是非常廣泛的,本文主要介紹了基于C++11實(shí)現(xiàn)手寫(xiě)線程池的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-08-08
  • 淺析c語(yǔ)言中的內(nèi)存

    淺析c語(yǔ)言中的內(nèi)存

    在c++中,內(nèi)存分為5個(gè)區(qū),分別是棧區(qū),堆區(qū),自由存儲(chǔ)區(qū),全局/靜態(tài)存儲(chǔ)區(qū)和常量存儲(chǔ)區(qū).
    2017-09-09
  • 使用C++實(shí)現(xiàn)位圖處理

    使用C++實(shí)現(xiàn)位圖處理

    本文介紹了如何使用C++語(yǔ)言處理位圖圖像,包括讀取、修改、保存等操作。通過(guò)具體的代碼示例,讀者可以學(xué)習(xí)到如何利用C++中的位運(yùn)算、數(shù)組和文件操作等知識(shí)點(diǎn)完成位圖處理任務(wù)。同時(shí),本文也提供了一些常用的圖像處理算法供讀者參考,幫助讀者更好地理解位圖處理過(guò)程
    2023-04-04
  • C語(yǔ)言中回調(diào)函數(shù)的含義與使用場(chǎng)景詳解(2)

    C語(yǔ)言中回調(diào)函數(shù)的含義與使用場(chǎng)景詳解(2)

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言中回調(diào)函數(shù)的含義與使用場(chǎng)景,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-03-03
  • C語(yǔ)言超詳細(xì)講解棧的實(shí)現(xiàn)及代碼

    C語(yǔ)言超詳細(xì)講解棧的實(shí)現(xiàn)及代碼

    棧(stack)又名堆棧,它是一種運(yùn)算受限的線性表。限定僅在表尾進(jìn)行插入和刪除操作的線性表。這一端被稱(chēng)為棧頂,相對(duì)地,把另一端稱(chēng)為棧底。向一個(gè)棧插入新元素又稱(chēng)作進(jìn)棧、入?;驂簵?,它是把新元素放到棧頂元素的上面,使之成為新的棧頂元素
    2022-04-04
  • C/C++使用C語(yǔ)言實(shí)現(xiàn)多態(tài)

    C/C++使用C語(yǔ)言實(shí)現(xiàn)多態(tài)

    這篇文章主要介紹了C/C++多態(tài)的實(shí)現(xiàn)機(jī)制理解的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下,希望能給你帶來(lái)幫助
    2021-08-08

最新評(píng)論

屏东市| 苍溪县| 高雄市| 尤溪县| 绥宁县| 安图县| 克山县| 吴江市| 乌鲁木齐市| 云和县| 濉溪县| 昌乐县| 冷水江市| 博罗县| 沙坪坝区| 嵩明县| 贺兰县| 公安县| 尖扎县| 桐柏县| 和龙市| 汽车| 石阡县| 慈溪市| 家居| 湘乡市| 囊谦县| 宁河县| 富锦市| 琼结县| 晋州市| 辽宁省| 南郑县| 河西区| 云和县| 海门市| 雅安市| 双流县| 韩城市| 酒泉市| 穆棱市|