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

c++ 排查內存泄漏的妙招

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

前言

對于c++而言,如何查找內存泄漏是程序員亙古不變的話題;解決之道可謂花樣繁多。因為最近要用到QT寫程序,擺在我面前的第一個重要問題是內存防泄漏。如果能找到一個簡單而行之有效的方法,對后續(xù)開發(fā)大有裨益。久思終得訣竅,本文就詳細介紹我對此問題的應對之策。(文末符完整代碼)

如何判斷內存有泄漏

  內存分配和釋放對應的操作是new、delete。如何判斷內存是否釋放干凈?其實判斷起來非常簡單:一個獨立的模塊整個生存周期內new的個數(shù)和delete的個數(shù)相等。用偽代碼標示如下:

int newCount = 0;
 int deleteCount = 0;

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

 //delete 操作時
 delete* objPtr;
 deleteCount++;

 //模塊結束時
 if(newCount != deleteCount)
 {
 內存有泄漏
 }

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

我們的方法有如下特點:

1 使用起來超級簡單,不增加開發(fā)難度。

2 發(fā)生內存泄漏時,能定位到具體是哪個類。

托管new delete 操作符

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

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

public:
 MemManage();

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

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

 //new操作 構造函數(shù)有2個參數(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)
 {
 //操作符對應的類名稱
 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;
 }
 }
}

如何使用輔助類

   使用起來很簡單,示例代碼如下:

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

//new操作,需根據構造函數(shù)的參數(shù)個數(shù)調用對應的函數(shù)
//構造函數(shù) 沒有參數(shù)
QFile* file = MemManage::instance()->New<QFile>();

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

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

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

 一個模塊調用周期結束 調用下列代碼,查看是否有內存泄漏:

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

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

進一步定位內存泄漏問題

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

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

建立一個map表,記錄類名對應的操作信息:

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

//map對照表
QMap<QString, MemObjInfo*> _mapMemObjCount;

//按類名統(tǒng)計
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++;
 }
 }
}

如果有內存泄漏 則會輸出如下信息:

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

輔助類完整代碼:

#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

后記 

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

以上就是c++ 防止內存泄漏的妙招的詳細內容,更多關于c++ 防止內存泄漏的資料請關注腳本之家其它相關文章!

相關文章

  • C語言詳細講解while語句的用法

    C語言詳細講解while語句的用法

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

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

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

    C++中棧結構建立與操作詳細解析

    我們可以把棧理解成一個大倉庫,放在倉庫門口(棧頂)的貨物會優(yōu)先被取出,然后再取出里面的貨物。而從數(shù)據的邏輯結構來看,棧結構起始就是一種線性結構
    2013-10-10
  • C++深入刨析優(yōu)先級隊列priority_queue的使用

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

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

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

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

    淺析c語言中的內存

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

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

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

    C語言中回調函數(shù)的含義與使用場景詳解(2)

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

    C語言超詳細講解棧的實現(xiàn)及代碼

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

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

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

最新評論

云安县| 武安市| 中卫市| 尼木县| 清水河县| 罗江县| 永兴县| 辽阳市| 丁青县| 大冶市| 五大连池市| 辽源市| 儋州市| 丹棱县| 个旧市| 宁国市| 贡嘎县| 鄂尔多斯市| 汉源县| 大同县| 南皮县| 宁波市| 靖宇县| 抚宁县| 抚顺县| 长子县| 思茅市| 新泰市| 达拉特旗| 太仆寺旗| 铁岭县| 海南省| 天镇县| 甘洛县| 舞阳县| 清水河县| 庆阳市| 盐城市| 鄂尔多斯市| 黑河市| 尉氏县|