基於 crt debug 實現的 Windows 程式記憶體流失偵查工具

來源:互聯網
上載者:User

  Windows 程式記憶體流失檢測是一項十分重要的工作,基於 GUI 的應用程式通常在調試結束時也有記憶體流失報告,但這個報告的資訊不全面,不能定位到產生泄漏的具體行號。其實自己實現一個記憶體流失偵查工具是一件非常簡單的事情,但看過網上寫的很多例子,普遍存在兩種問題:

    1. 要麼考慮不周全,一種環境下能用,而在另外一種環境下卻不能很好工作,或者漏洞報告的輸出方式不合理。
    2. 要麼過於保守,例如:完全沒有必要在 _malloc_dbg() 和 _free_dbg() 的調用前後用 CriticalSection 進行保護(跟蹤一下多線程環境下 new 和 malloc 的代碼就會明白)。

  記憶體檢測主要用到以下幾個 API,這些 API 能跟蹤 new 和 malloc 系列方法申請的記憶體,具體說明參考說明文檔:

struct _CrtMemState;

_CrtSetDbgFlag();
_CrtMemCheckpoint();
_CrtMemCheckpoint();
_CrtMemDifference();
_CrtMemDumpStatistics();
_malloc_dbg();
_free_dbg();

 

  •   標頭檔:win32_crtdbg.h
#pragma once

#if defined _DEBUG && defined _DETECT_MEMORY_LEAK

#ifdef new
#undef new
#endif

#ifdef delete
#undef delete
#endif

#ifndef _CRTDBG_MAP_ALLOC
#define _CRTDBG_MAP_ALLOC
#endif

#include <crtdbg.h>

namespace __dbg_impl
{
class CDebugEnv
{
public:
CDebugEnv()
{
::_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
::_CrtMemCheckpoint(&s1);
}

~CDebugEnv()
{
::_CrtMemCheckpoint(&s2);

if (::_CrtMemDifference( &s3, &s1, &s2))
{
TRACE0("!! Memory stats !!\n");
TRACE0("----------------------------------------\n");
::_CrtMemDumpStatistics(&s3);
TRACE0("----------------------------------------\n");
}
}

private:
_CrtMemState s1, s2, s3;
};

static __dbg_impl::CDebugEnv __dbgEnv;
}

inline void* __cdecl operator new(size_t nSize, const char* lpszFileName, int nLine)
{
return ::_malloc_dbg(nSize, _NORMAL_BLOCK, lpszFileName, nLine);
}

inline void* __cdecl operator new[](size_t nSize, const char* lpszFileName, int nLine)
{
return operator new(nSize, lpszFileName, nLine);
}

inline void* __cdecl operator new(size_t nSize)
{
return operator new(nSize, __FILE__, __LINE__);
}

inline void* __cdecl operator new[](size_t nSize)
{
return operator new(nSize, __FILE__, __LINE__);
}

inline void* __cdecl operator new(size_t nSize, const std::nothrow_t&)
{
return operator new(nSize, __FILE__, __LINE__);
}

inline void* __cdecl operator new[](size_t nSize, const std::nothrow_t&)
{
return operator new(nSize, __FILE__, __LINE__);
}

inline void __cdecl operator delete(void* p)
{
::_free_dbg(p, _NORMAL_BLOCK);
}

inline void __cdecl operator delete[](void* p)
{
operator delete(p);
}

inline void __cdecl operator delete(void* p, const char* lpszFileName, int nLine)
{
operator delete(p);
}

inline void __cdecl operator delete[](void* p, const char* lpszFileName, int nLine)
{
operator delete(p);
}

inline void __cdecl operator delete(void *p, const std::nothrow_t&)
{
operator delete(p);
}

inline void __cdecl operator delete[](void *p, const std::nothrow_t&)
{
operator delete(p);
}

#define new new(__FILE__, __LINE__)

#endif // _DEBUG && defined _DETECT_MEMORY_LEAK

 

  •   實現檔案:win32_crtdbg.cpp
#include "stdafx.h"
#include "win32_crtdbg.h"

#if defined _DEBUG && defined _DETECT_MEMORY_LEAK

__dbg_impl::CDebugEnv __dbgEnv;

#endif // _DEBUG && defined _DETECT_MEMORY_LEAK

 

  • 使用方法
    1. 在 stdafx.h 或其他公用標頭檔中: #define_DETECT_MEMORY_LEAK,#include"win32_crtdbg.h"。
    2. 刪除項目工程模板中自動產生的 new 操作符重定義,通常自動產生的 cpp 檔案在 DEBUG 環境下會把 new 重定義為 DEBUG_NEW。
  • 存在問題

    對於某些全域變數指向的堆記憶體,如果 ~CDebugEnv() 被調用之時還沒釋放,則可能存在誤判現象。這是一個老大難問題了,目前還沒有完美的解決方案。

CodeProject

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.