js333 > 计算机互联网 > NSLog以便发版和调试,程序内存泄漏检测工具

原标题:NSLog以便发版和调试,程序内存泄漏检测工具

浏览次数:179 时间:2019-11-13

C++ VS2012 内存泄露检测,vs2012泄露

在VS2012中添加部分代码,可以起到检测内存泄露的作用。

今天刚刚收到的解决办法,原理还不是很清楚。先分享出来

 

  1. 头文件中添加以下代码

    #ifdef _DEBUG
    #define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, FILE, LINE)
    #else
    #define DEBUG_CLIENTBLOCK
    #endif
    #define _CRTDBG_MAP_ALLOC
    #include
    #include
    #ifdef _DEBUG
    #define new DEBUG_CLIENTBLOCK
    #endif
    / 何问起 hovertree.com /

  2. main函数中添加

    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);
    / 何问起 hovertree.com /

程序在DEBUG模式下运行时,就可以在输出窗口中看到可能出现的内存泄露信息

推荐:

VS2012 内存泄露检测,vs2012泄露 在VS2012中添加部分代码,可以起到检测内存泄露的作用。 今天刚刚收到的解决办法,原理还不是很清楚。...

  Windows 程序内存泄漏检测是一项十分重要的工作,基于 GUI 的应用程序通常在调试结束时也有内存泄漏报告,但这个报告的信息不全面,不能定位到产生泄漏的具体行号。其实自己实现一个内存泄漏检测工具是一件非常简单的事情,但看过网上写的很多例子,普遍存在两种问题:

怎样对一个程序实现的功能移植到已有的一个大MFC项目中?
1// HttpPost.cpp written by l_zhaohui@163.com 2// 2007/11/30 3#include "stdafx.h" 4#include 5#include 6#include 7 8#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS 9#include 10#include 11 12#define USE_WINHTTP //Comment this line to user wininet. 13#ifdef USE_WINHTTP 14 #include 15 #pragma comment(lib, "winhttp.lib") 16#else 17 #include 18 #pragma comment(lib, "wininet.lib") 19#endif 20#define BUF_SIZE 21 22// CrackedUrl 23class CrackedUrl { 24 int m_scheme; 25 CStringW m_host; 26 int m_port; 27 CStringW m_path; 28public: 29 CrackedUrl(LPCWSTR url) 30 { 31 URL_COMPONENTS uc = { 0}; 32 uc.dwStructSize = sizeof; 33 34 const DWORD BUF_LEN = 256; 35 36 WCHAR host[BUF_LEN]; 37 uc.lpszHostName = host; 38 uc.dwHostNameLength = BUF_LEN; 39 40 WCHAR path[BUF_LEN]; 41 uc.lpszUrlPath = path; 42 uc.dwUrlPathLength = BUF_LEN; 43 44 WCHAR extra[BUF_LEN]; 45 uc.lpszExtraInfo = extra; 46 uc.dwExtraInfoLength = BUF_LEN; 47 48#ifdef USE_WINHTTP 49 if (!WinHttpCrackUrl(url, 0, ICU_ESCAPE, &uc)) { 50 printf("Error:WinHttpCrackUrl failed!/n"); 51 } 52 53#else 54 if (!InternetCrackUrl(url, 0, ICU_ESCAPE, &uc)) { 55 printf("Error:InternetCrackUrl failed!/n"); 56 } 57#endif 58 m_scheme = uc.nScheme; 59 m_host = host; 60 m_port = uc.nPort; 61 m_path = path; 62 } 63 64 int GetScheme() const 65 { 66 return m_scheme; 67 } 68 69 LPCWSTR GetHostName() const 70 { 71 return m_host; 72 } 73 74 int GetPort() const 75 { 76 return m_port; 77 } 78 79 LPCWSTR GetPath() const 80 { 81 return mpath; 82 } 83 84 static CStringA UrlEncode(const char* p) 85 { 86 if { 87 return CStringA(); 88 } 89 90 CStringA buf; 91 92 for { 93 int ch = ; 94 if (ch == '/0') { 95 break; 96 } 97 98 if (isalnum || ch == '' || ch == '-' || ch == '.') { 99 buf += ch;100 }101 else if (ch == ' ') {102 buf += '+';103 }104 else {105 char c[16];106 wsprintfA(c, "%%%02X", ch);107 buf += c;108 }109 }110111 return buf;112 }113};114115// CrackedUrl116HINTERNET OpenSession(LPCWSTR userAgent = 0)117{118#ifdef USE_WINHTTP119 return WinHttpOpen(userAgent, NULL, NULL, NULL, NULL);;120#else121 return InternetOpen(userAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);122#endif123}124125HINTERNET Connect(HINTERNET hSession, LPCWSTR serverAddr, int portNo)126{127#ifdef USE_WINHTTP128 return WinHttpConnect(hSession, serverAddr, (INTERNET_PORT) portNo, 0);129#else130 return InternetConnect(hSession, serverAddr, portNo, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);131#endif132}133134HINTERNET OpenRequest(HINTERNET hConnect, LPCWSTR verb, LPCWSTR objectName, int scheme)135{136 DWORD flags = 0;137#ifdef USE_WINHTTP138 if (scheme == INTERNET_SCHEME_HTTPS) {139 flags |= WINHTTP_FLAG_SECURE;140 }141142 return WinHttpOpenRequest(hConnect, verb, objectName, NULL, NULL, NULL, flags);143144#else145 if (scheme == INTERNET_SCHEME_HTTPS) {146 flags |= INTERNET_FLAG_SECURE;147 }148149 return HttpOpenRequest(hConnect, verb, objectName, NULL, NULL, NULL, flags, 0);150#endif151}152153BOOL AddRequestHeaders(HINTERNET hRequest, LPCWSTR header)154{155 SIZE_T len = lstrlenW;156#ifdef USE_WINHTTP157 return WinHttpAddRequestHeaders(hRequest, header, DWORD, WINHTTP_ADDREQ_FLAG_ADD);158#else159 return HttpAddRequestHeaders(hRequest, header, DWORD, HTTP_ADDREQ_FLAG_ADD);160#endif161}162163BOOL SendRequest(HINTERNET hRequest, const void body, DWORD size)164{165#ifdef USE_WINHTTP166 return WinHttpSendRequest(hRequest, 0, 0, const_cast>, size, size, 0);167#else168 return HttpSendRequest(hRequest, 0, 0, const_cast>, size);169#endif170}171172BOOL EndRequest(HINTERNET hRequest)173{174#ifdef USE_WINHTTP175 return WinHttpReceiveResponse(hRequest, 0);176#else177 // if you use HttpSendRequestEx to send request then use HttpEndRequest in here!178 return TRUE;179#endif180}181182BOOL QueryInfo(HINTERNET hRequest, int queryId, char szBuf, DWORD pdwSize)183{184#ifdef USE_WINHTTP185 return WinHttpQueryHeaders(hRequest, queryId, 0, szBuf, pdwSize, 0);186#else187 return HttpQueryInfo(hRequest, queryId, szBuf, pdwSize, 0);188#endif189}190191BOOL ReadData(HINTERNET hRequest, void buffer, DWORD length, DWORD cbRead)192{193#ifdef USE_WINHTTP194 return WinHttpReadData(hRequest, buffer, length, cbRead);195#else196 return InternetReadFile(hRequest, buffer, length, cbRead);197#endif198}199200void CloseInternetHandle(HINTERNET hInternet)201{202 if (hInternet)203 {204#ifdef USE_WINHTTP205 WinHttpCloseHandle(hInternet);206#else207 InternetCloseHandle(hInternet);208#endif209 }210}211212int _tmain(int argc, _TCHAR argv[])213{214 HINTERNET hSession = 0;215 HINTERNET hConnect = 0;216 HINTERNET hRequest = 0;217 CStringW strHeader(L"Content-type: application/x-www-form-urlencoded/r/n");218219 // Test data220 CrackedUrl crackedUrl(L" CStringA strPostData("value1=10&value2=14");222223 // Open session.224 hSession = OpenSession(L"HttpPost by l_zhaohui@163.com");225 if (hSession == NULL) {226 printf("Error:Open session!/n");227 return -1;228 }229230 // Connect.231 hConnect = Connect(hSession, crackedUrl.GetHostName(), crackedUrl.GetPort;232 if (hConnect == NULL) {233 printf("Error:Connect failed!/n");234 return -1;235 }236237 // Open request.238 hRequest = OpenRequest(hConnect, L"POST", crackedUrl.GetPath(), crackedUrl.GetScheme;239 if (hRequest == NULL) {240 printf("Error:OpenRequest failed!/n");241 return -1;242 }243244 // Add request header.245 if (!AddRequestHeaders(hRequest, strHeader)) {246 printf("Error:AddRequestHeaders failed!/n");247 return -1;248 }249250 // Send post data.251 if (!SendRequest(hRequest, (const char*)strPostData, strPostData.GetLength {252 printf("Error:SendRequest failed!/n");253 return -1;254 }255256 // End request257 if (!EndRequest) {258 printf("Error:EndRequest failed!/n");259 return -1;260 }261262 char szBuf[BUF_SIZE];263 DWORD dwSize = 0;264 szBuf[0] = 0;265266 // Query header info.267#ifdef USE_WINHTTP268 int contextLengthId = WINHTTP_QUERY_CONTENT_LENGTH;269 int statusCodeId = WINHTTP_QUERY_STATUS_CODE;270 int statusTextId = WINHTTP_QUERY_STATUS_TEXT;271#else272 int contextLengthId = HTTP_QUERY_CONTENT_LENGTH;273 int statusCodeId = HTTP_QUERY_STATUS_CODE;274 int statusTextId = HTTP_QUERY_STATUS_TEXT;275#endif276 dwSize = BUF_SIZE;277 if (QueryInfo(hRequest, contextLengthId, szBuf, &dwSize)) {278 szBuf[dwSize] = 0;279 printf("Content length:[%s]/n", szBuf);280 }281282 dwSize = BUF_SIZE;283 if (QueryInfo(hRequest, statusCodeId, szBuf, &dwSize)) {284 szBuf[dwSize] = 0;285 printf("Status code:[%s]/n", szBuf);286 }287288 dwSize = BUF_SIZE;289 if (QueryInfo(hRequest, statusTextId, szBuf, &dwSize)) {290 szBuf[dwSize] = 0;291 printf("Status text:[%s]/n", szBuf);292 }293294 // read data.295 for {296 dwSize = BUF_SIZE;297 if (ReadData(hRequest, szBuf, dwSize, &dwSize) == FALSE) {298 break;299 }300301 if (dwSize <= 0) {302 break;303 }304305 szBuf[dwSize] = 0;306 printf("%s/n", szBuf); //Output value = value1 + value2307 }308309 CloseInternetHandle;310 CloseInternetHandle;311 CloseInternetHandle;312313 return 0;314}

问题

  • 开发中用了大量的 NSLog,但是发布时想取消这些 NSLog
  • 开发中是否经常用过 NSLog(@"%s", __FUNCTION__);
    1. 要么考虑不周全,一种环境下能用,而在另外一种环境下却不能很好工作,或者漏洞报告的输出方式不合理。
    2. 要么过于保守,例如:完全没有必要在 _malloc_dbg() 和 _free_dbg() 的调用前后用 CriticalSection 进行保护(跟踪一下多线程环境下 new 和 malloc 的代码就会明白)。

这是一个使用WinHTTP协议发送数据的完整程序。
在我已有的VC工程中怎么添加对应的http.h和http.cpp文件,方便调用其中的主函数?
小弟初学者,谢谢了

解决问题

  • 新建 ExtendNSLog 类,继承自 NSObject
  • 在 ExtendNSLog.h 中删除默认代码
  • 添加以下函数声明:

    void ExtendNSLog(const char file, int lineNumber, const char functionName, NSString *format, ...);

  • 在 ExtendNSLog.m 中删除默认代码

  • 添加以下代码实现:

    1 void ExtendNSLog(const char file, int lineNumber, const char functionName, NSString format, ...) { 2 3 va_list ap; 4 5 va_start(ap, format); 6 7 if (![format hasSuffix: @"n"]) { 8 format = [format stringByAppendingString: @"n"]; 9 } 10 11 NSString body = [[NSString alloc] initWithFormat:format arguments:ap]; 12 13 va_end(ap); 14 15 NSString *fileName = [[NSString stringWithUTF8String:file] lastPathComponent]; 16 fprintf(stderr, "(%s) (%s:%d) %s", 17 functionName, 18 [fileName UTF8String], 19 lineNumber, 20 [body UTF8String]); 21 }

  • 新建 PrefixHeader.pch 文件

  • 输入以下内容:

    1 #ifdef OBJC 2 3 #import 4 #import 5 6 #import "ExtendNSLog.h" 7 8 #ifdef DEBUG 9 #define NSLog(args...) ExtendNSLog(FILE, LINE, PRETTY_FUNCTION, args); 10 #else 11 #define NSLog(x...) 12 #endif 13 14 #endif

  • 选择 项目->TARGETS->[ProjectName]->Build Settings

  • 在搜索框输入 prefix header
  • 在 Prefix Header中输入 [ProjectName]/PrefixHeader.pch

``如下图所示

金沙js333娱乐场 1

  • 运行测试,如下图修改运行模式

金沙js333娱乐场 2

 

  内存检测主要用到以下几个 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

    namespace 金沙js333娱乐场,__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 {

    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 {

    return operator new(nSize, __FILE__, __LINE__);
    

    }

    inline void __cdecl operator delete(void* p) {

    ::_free_dbg(p, _NORMAL_BLOCK);
    

    }

    inline void __cdecl operator delete {

    operator delete(p);
    

    }

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

    operator delete(p);
    

    }

    inline void __cdecl operator delete {

    operator delete(p);
    

    }

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

    operator delete(p);
    

    }

    inline void __cdecl operator delete {

    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

本文由js333发布于计算机互联网,转载请注明出处:NSLog以便发版和调试,程序内存泄漏检测工具

关键词:

上一篇:的使用详解,遇到不懂的

下一篇:没有了