Chinaunix首页 | 论坛 | 博客
  • 博客访问: 339516
  • 博文数量: 88
  • 博客积分: 1695
  • 博客等级: 上尉
  • 技术积分: 1380
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-06 15:48
个人简介

喜欢美食, 旅行..

文章分类

全部博文(88)

文章存档

2014年(2)

2013年(12)

2012年(14)

2010年(8)

2009年(52)

我的朋友

分类: C/C++

2012-12-05 21:31:21

这个例子只是一个简单的内存跟踪方案, 思路很简单.
Step 1. 对现有的内存内配的函数做一个包装.< 可用 windows核心编程 里面介绍的API拦截方案 >
Step 2. 申请的时候记录当前行号, 释放的时候取消记录.
Step 3. 进程结束的时候打印所有未释放的申请记录.
注释: 考虑到多线程问题, 为了避免读写记录的时候有线程的竞争现象, 所以每个线程都有自己独立的记录结构, 不做任何交互, 等到进程结束的时候才统一清算. 示例代码如下:

  1. #include <string>
  2. #include <map>
  3. #include <set>

  4. #ifdef _WIN32
  5. #include <windows.h>
  6. inline unsigned long
  7. currentThreadID(void){ return GetCurrentThreadId();}

  8. #ifdef _DEBUG
  9. inline void output(std::string strInfo)
  10. { ::OutputDebugStringA(strInfo.c_str()); }
  11. #else
  12. #include <iostream>
  13. inline void output(std::string strInfo)
  14. { std::cout << strInfo << std::flush; }
  15. #endif
  16. #endif

  17. // 记录内存分配情况的结构框架.
  18. struct MemoryRecords
  19. {
  20.     std::map< unsigned long, std::map<void*,std::string> > m_AllocInfos;
  21.     std::map< void*, unsigned long > m_freeInfos;
  22.     ~MemoryRecords()
  23.     {
  24.         std::map< unsigned long, std::map<void*,std::string>
  25.             >::iterator itOut = m_AllocInfos.begin();
  26.         for ( ; itOut != m_AllocInfos.end(); ++itOut )
  27.         {
  28.             std::map<void*,std::string>::iterator itIn = itOut->second.begin();
  29.             for ( ; itIn != itOut->second.end(); ++itIn )
  30.             {
  31.                 bool needToOutputInfo = true;
  32.                 if ( m_freeInfos.find(itIn->first) != m_freeInfos.end() )
  33.                 {
  34.                     if ( m_freeInfos[itIn->first] > 0 )
  35.                     {
  36.                         m_freeInfos[itIn->first] -= 1;
  37.                         needToOutputInfo = false;
  38.                     }
  39.                 }
  40.                 if ( needToOutputInfo ) output(itIn->second);
  41.             }
  42.         }
  43.     }
  44. };
  45. MemoryRecords g_memRecords;

  46. // 申请内存 的 入口包装函数.
  47. void * operator new(unsigned int size,char* file, int line)
  48. {
  49.     char strLine[64] = {0};
  50.     _itoa_s(line,strLine,10);

  51.     char strBytes[64] = {0};
  52.     _itoa_s(size,strBytes,10);

  53.     std::string strInfo;
  54.     strInfo.append(file).append("(").append(strLine).append(") : ");
  55.     strInfo.append("Here are ").append(strBytes).append(" btyes memory missed to be free, please check !\n");
  56.     
  57.     void * memory = operator new (size);

  58.     // 有内存的内配活动, 记录当前的文件和行号.
  59.     g_memRecords.m_AllocInfos[currentThreadID()][memory] = strInfo;

  60.     return memory;
  61. }

  62. // 释放内存 的 入口包装函数.
  63. void release(void * memory)
  64. {
  65.     std::map<void*,std::string> & mapAlloc
  66.         = g_memRecords.m_AllocInfos[currentThreadID()];
  67.     std::map< void*, unsigned long > & mapFree
  68.         =g_memRecords.m_freeInfos;

  69.     if ( mapAlloc.find(memory) != mapAlloc.end() ) {
  70.               // 有内存被释放, 如果和申请在同一个线程就直接清除记录.
  71.         mapAlloc.erase(memory);
  72.     } else { // 否则, 就记录这一次释放, 方便最后的清算.
  73.         if (mapFree.find(memory) != mapFree.end() )
  74.             mapFree[memory] = 1;
  75.         else mapFree[memory] += 1;
  76.     }

  77.     operator delete(memory); memory = NULL;
  78. }

  79. #ifdef _DEBUG
  80. #define new new(__FILE__, __LINE__)
  81. #endif
最后附上简单的测试代码. 如下:

  1. void test_new()
  2. {
  3.     int * p1 = new int;
  4.     int * p2 = new int;

  5.     release(p1); p1 = NULL;
  6. }

  7. int main()
  8. {
  9.     test_new();
  10.     return 0;
  11. }
我是在VC上面测试的,双击输出框的打印结果能直接定位到申请内存的位置. 如下:

  1. ..............
  2. d:\src-project\basictest\basictest\test.cpp(98) : Here are 4 btyes memory missed to be free, please check !
  3. 程序“[9624] basicTest.exe: 本机”已退出,返回值为 0 (0x0)

阅读(1963) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~