欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

前言

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

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

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

int newCount = 0;
 int deleteCount = 0;

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

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

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

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

我們的方法有如下特點:

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

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

托管new delete 操作符

  要跟蹤所有的new、delete操作,最簡單的辦法就是托管new、delete。不直接調(diào)用系統(tǒng)的操作符,而是用我們自己寫的函數(shù)處理。在我們的函數(shù)內(nèi)部,則別有洞天; 對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操作 構(gòu)造函數(shù)沒有參數(shù)
 template <typename T>
 T* New()
 {
 ShowOperationMessage<T>(true);
 return new T();
 };

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

 //new操作 構(gòu)造函數(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操作,需根據(jù)構(gòu)造函數(shù)的參數(shù)個數(shù)調(diào)用對應的函數(shù)
//構(gòu)造函數(shù) 沒有參數(shù)
QFile* file = MemManage::instance()->New<QFile>();

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

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

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

 一個模塊調(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,則沒內(nèi)存泄漏
 total New : 166 Delete : 6 leftNew : 160

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

  通過判斷new和delete的個數(shù)是否相等,只是知道了是否有內(nèi)存泄漏;進一步定位問題,才能方便我們解決問題。如果能定位到操作哪一個類時,發(fā)生了內(nèi)存泄漏,則問題范圍就大大縮小。我們可以按類名,記錄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++;
 }
 }
}

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

如上圖,對5個類的操作發(fā)送了內(nèi)存泄漏。比如我們知道了類OfdDocumentPageAttr發(fā)生內(nè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)存泄漏的方法很多。本文介紹了一種行之有效的方法。開發(fā)一個新項目前,就需確定如何跟蹤定位內(nèi)存泄漏,發(fā)現(xiàn)問題越早解決起來越簡單。程序開發(fā)是循序漸進的過程,一個功能模塊開發(fā)完成后,需及早確定是否有內(nèi)存泄漏。防微杜漸,步步為營,方能產(chǎn)出高質(zhì)量的產(chǎn)品。

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

相關文章

  • C語言中的switch語句基本用法

    C語言中的switch語句基本用法

    這篇文章主要介紹了C語言中switch語句的基本用法,switch語句是一個多分支選擇語句,并且可以支持嵌套,感興趣的同學可以參考閱讀
    2023-03-03
  • C++中stack、queue、vector的用法詳解

    C++中stack、queue、vector的用法詳解

    本文通過實例代碼給大家介紹了C++中stack、queue、vector的用法,需要的朋友參考下吧
    2017-08-08
  • c++ vector造成的內(nèi)存泄漏問題

    c++ vector造成的內(nèi)存泄漏問題

    這篇文章主要介紹了c++ vector造成的內(nèi)存泄漏問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • QT中幾種常用的排序函數(shù)用法總結(jié)

    QT中幾種常用的排序函數(shù)用法總結(jié)

    Qt是目前最先進、最完整的跨平臺C++開發(fā)工具,下面這篇文章主要給大家介紹了關于QT中幾種常用的排序函數(shù)用法的相關資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-01-01
  • C++帶有指針成員的類處理方式詳解

    C++帶有指針成員的類處理方式詳解

    這篇文章主要為大家詳細介紹了C++帶有指針成員的類處理方式,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • c++重載的詳細總結(jié)

    c++重載的詳細總結(jié)

    作為成員函數(shù)重載符,對于雙目操作符重載函數(shù)只需一個形參,對于單目操作符重載函數(shù)不需要形參
    2013-09-09
  • C語言中if語句加大括號和不加大括號的區(qū)別介紹

    C語言中if語句加大括號和不加大括號的區(qū)別介紹

    這篇文章主要給大家介紹了關于C語言中if語句加大括號和不加大括號的區(qū)別,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-12-12
  • C語言的程序環(huán)境與預處理你真的了解嗎

    C語言的程序環(huán)境與預處理你真的了解嗎

    這篇文章主要為大家詳細介紹了C語言的程序環(huán)境與預處理,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • OpenCV實現(xiàn)更改圖片顏色功能

    OpenCV實現(xiàn)更改圖片顏色功能

    這篇文章主要為大家詳細介紹了如何利用OpenCV實現(xiàn)更改圖片顏色的功能,文中代碼介紹詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-05-05
  • 簡單對比C語言中的fputs()函數(shù)和fputc()函數(shù)

    簡單對比C語言中的fputs()函數(shù)和fputc()函數(shù)

    這篇文章主要介紹了簡單對比C語言中的fputs()函數(shù)和fputc()函數(shù),注意其之間的區(qū)別,需要的朋友可以參考下
    2015-08-08

最新評論