很久没有写技术方面的东西了,这半年主要是在学习别人的东西,对自己提高比较大,算是一次技术回笼吧,这次学习之旅目的是结束技术方面的专注,开始向应用方面找突破口,也就是完成技术积累或者为技术的积累做坚实的准备。

c/C++的一个让人疯狂的地方就是内存管理,非法访问、越界、野指针、泄漏、内存分配器等诸多问题,有时候一个编程老手也会迷惘困惑。Crt有一些堆栈检查的函数可以完成基本的内存状况检查,MFC也有一些简单的对象检查机制,当然好的算是java、.net等sdk的超重量级封装了,即使发生对象错误也能把堆栈信息明明白白的告诉你(至少表面上是这样,具体我对这两种语言没有做过开发)。下面介绍的是某牛公司实现的内存分配工具,基本实现了内存泄漏检查,对象合法性检查,对于我来说已经够用了。

为了对内存分配块进行跟踪,设计如下结构体:

//+--------------------------------------------------------------
//
// 每个请求分配内存块的前缀结构体
// 用来跟踪所有请求分配块以及请求分配名称
//
//---------------------------------------------------------------
struct DBGALLOCHDR
{
    DBGALLOCHDR*    pdbgahPrev; // 前一个内存块头
    DBGALLOCHDR*    pdbgahNext; // 后一个内存块头
    DWORD           iAllocated; // 记录是第几次请求分配操作
    DWORD           tid;        // 请求分配线程的ID
    size_t          cbRequest;  // 请求分配大小
    char            szName[64]; // 请求分配块名称
    DWORD           adwGuard[4];// 保护头
};

//+--------------------------------------------------------------
//
// 每个请求分配内存块的后缀结构体
// 使用特定的数据填充用来检测指针是合法
//
//---------------------------------------------------------------
struct DBGALLOCFOOT
{
    DWORD adwGuard[4];
};

// 内存跟踪块的根,通过根可以获取所有分配块
DBGALLOCHDR g_dbgahRoot =
{
    &g_dbgahRoot,
    &g_dbgahRoot,
    0,
    (DWORD)-1
};

为了实现多线程内存分配跟踪,采用Tls技术使用线程局部对象保存当前分配信息:

// 线程局部对象结构体,辅助实现每个线程的请求内存分配记录
struct DBGTHREADSTATE
{
    DBGTHREADSTATE* ptsNext;
    DBGTHREADSTATE* ptsPrev;

    // Add globals below
    void*           pvRequest;  // 线程最后一次请求分配内存的指针
    size_t          cbRequest;  // 线程最后一次请求分配内存的大小
};



// 调试期间实际分配内存大小=请求分配+分配头+分配尾
size_t _ActualSizeFromRequestSize(size_t cb)
{
    return cb+sizeof(DBGALLOCHDR)+sizeof(DBGALLOCFOOT);
}

主要实现的内存分配工具有如下这些:

void*   _MemAlloc(ULONG cb);
void*   _MemAllocClear(ULONG cb);
HRESULT _MemRealloc(void** ppv, ULONG cb);
ULONG   _MemGetSize(void* pv);
void    _MemFree(void* pv);
HRESULT _MemAllocString(LPCTSTR pchSrc, LPTSTR* ppchDst);
HRESULT _MemAllocString(ULONG cch, LPCTSTR pchSrc, LPTSTR* ppchDst);
HRESULT _MemReplaceString(LPCTSTR pchSrc, LPTSTR* ppchDest);

#define MemAlloc(cb)                            _MemAlloc(cb)
#define MemAllocClear(cb)                       _MemAllocClear(cb)
#define MemRealloc(ppv, cb)                     _MemRealloc(ppv, cb)
#define MemGetSize(pv)                          _MemGetSize(pv)
#define MemFree(pv)                            _MemFree(pv)
#define MemAllocString(pch, ppch)               _MemAllocString(pch, ppch)
#define MemAllocStringBuffer(cch, pch, ppch)    _MemAllocString(cch, pch, ppch)
#define MemReplaceString(pch, ppch)             _MemReplaceString(pch, ppch)
#define MemFreeString(pch)                      _MemFree(pch)

通过宏实现类的new delete重写:

#define DECLARE_MEMALLOC_NEW_DELETE() \
    inline void* __cdecl operator new(size_t cb)    { return(MemAlloc(cb)); } \
    inline void* __cdecl operator new[](size_t cb)  { return(MemAlloc(cb)); } \
    inline void __cdecl operator delete(void* pv)   { MemFree(pv); }

#define DECLARE_MEMCLEAR_NEW_DELETE() \
    inline void* __cdecl operator new(size_t cb)    { return(MemAllocClear(cb)); } \
    inline void* __cdecl operator new[](size_t cb)  { return(MemAllocClear(cb)); } \
    inline void __cdecl operator delete(void* pv)   { MemFree(pv); }

在应用的时候可以重写全局new delete:

// 测试全局new delete
void* __cdecl operator new(size_t cb)    { return(MemAlloc(cb)); }
void* __cdecl operator new[](size_t cb)  { return(MemAlloc(cb)); }
void __cdecl operator delete(void* pv)   { MemFree(pv); }

使用注意:
进程启动时候需要调用:
_DbgDllProcessAttach();
_afxGlobalData._hProcessHeap = GetProcessHeap();

进程退出的时候需要调用:
_DbgDllProcessDetach();

测试用例:

// 测试基本类型
void TestBuiltin()
{
    // 基本类型
    int* pInt = new int(10);
    int* pIntAry = new int[10];
    char* pStr = new char[100];
    MemSetName((pStr, "String"));
}

// 测试class
void TestClass()
{
    Cls* pCls = new Cls();
}

// 测试释放
void TestOk()
{
    Cls* pCls = new Cls();
    delete pCls;
    pCls = NULL;
}

DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
    int* pIntAry = new int[100];
    return 0;
}

// 测试多线程
void TestMultiThread()
{
    HANDLE hHandle = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
    WaitForSingleObject(hHandle, -1);
}

int main(int argc, char* argv[])
{
    _DbgDllProcessAttach();

    _afxGlobalData._hProcessHeap = GetProcessHeap();

    TestBuiltin();
    TestClass();
    TestMultiThread();
    TestOk();

    _DbgDllProcessDetach();
    return 0;
}

调试输出窗口结果:
A +    4 -    0 = [      4]
A +   40 -    0 = [     44]
A +  100 -    0 = [    144]
A +    8 -    0 = [    152]
A +  400 -    0 = [    552]
The thread 0x1D38 has exited with code 0 (0x0).
A +    8 -    0 = [    560]
F +    0 -    8 = [    552]
---------- Leaked Memory Blocks ----------
p=0x00144354  cb=400  #=4    TID:0x1d38 
p=0x00144294  cb=8    #=3    TID:0x1878 
p=0x001441a4  cb=100  #=2    TID:0x1878 String
p=0x001440ec  cb=40   #=1    TID:0x1878 
p=0x00142a54  cb=4    #=0    TID:0x1878 
total size 552, peak size 560
---------- Leaked Memory Blocks End ------

其中A表示分配 F表示释放

该工具本人初试没有中毒症状,打算纳入个人小宝库中,希望大家喜欢!

下载

http://www.cppblog.com/wlwlxj/archive/2009/06/03/86660.html

技术回归01-Windows内存分配工具的更多相关文章

  1. 01 Java 内存分配全面浅析

    http://blog.csdn.net/shimiso/article/details/8595564 Java 内存分配全面浅析  本文将由浅入深详细介绍Java内存分配的原理,以帮助新手更轻松的 ...

  2. windows 内存分配回收检查工具

    LeakDiag是微软一款检测memory leak的工具,使用比较简单 首先去下载一个ftp://ftp.microsoft.com/PSS/Tools/Developer%20Support%20 ...

  3. 【java虚拟机序列】java中的垃圾回收与内存分配策略

    在[java虚拟机系列]java虚拟机系列之JVM总述中我们已经详细讲解过java中的内存模型,了解了关于JVM中内存管理的基本知识,接下来本博客将带领大家了解java中的垃圾回收与内存分配策略. 垃 ...

  4. 内存分配详解 malloc, new, HeapAlloc, VirtualAlloc,GlobalAlloc

    很多地方都会使用内存,内存使用过程中操作不当就容易崩溃,无法运行程序,上网Google学习一下,了解整理下他们之间的区别以及使用 ,获益匪浅 0x01 各自的定义和理解 (1)先看GlobalAllo ...

  5. Netty 中的内存分配浅析-数据容器

    本篇接续前一篇继续讲 Netty 中的内存分配.上一篇 先简单做一下回顾: Netty 为了更高效的管理内存,自己实现了一套内存管理的逻辑,借鉴 jemalloc 的思想实现了一套池化内存管理的思路: ...

  6. C++ Primer 学习笔记_98_特殊的工具和技术 --优化内存分配

    特殊的工具和技术 --优化内存分配 引言: C++的内存分配是一种类型化操作:new为特定类型分配内存,并在新分配的内存中构造该类型的一个对象.new表达式自己主动执行合适的构造函数来初始化每一个动态 ...

  7. 全面介绍Windows内存管理机制及C++内存分配实例(四):内存映射文件

    本文背景: 在编程中,很多Windows或C++的内存函数不知道有什么区别,更别谈有效使用:根本的原因是,没有清楚的理解操作系统的内存管理机制,本文企图通过简单的总结描述,结合实例来阐明这个机制. 本 ...

  8. 全面介绍Windows内存管理机制及C++内存分配实例

    转自:http://blog.csdn.net/yeming81/article/details/2046193 本文基本上是windows via c/c++上的内容,笔记做得不错.. 本文背景: ...

  9. 解决Windows内存问题的两个小工具RamMap和VMMap(这个更牛更好)

    来源:http://www.cr173.com/html/13006_1.html .net程序内存监测分配工具(CLR Profiler for .NET Framework 4)官方安装版 类型: ...

随机推荐

  1. Objective-C基础教程读书笔记(7)

    第7章 深入了解Xcode Xcode是一个很好用的工具,有很多强大的功能,不过并不是所有的功能都易于发现.如果你打算长期使用这个强大的工具,就肯定要尽可能多了解它.本章将介绍一些Xcode编辑器的使 ...

  2. 最全的LBS手机定位技术说明

    随着手机技术的发展定位方式也发生了非常大的变化.获取手机位置有非常多种方式. 第一种:CELL-ID定位原理 通过移动网络获取设备当前所在的Cell信息来获取设备当前位置.当设备位置更新设备会向当前服 ...

  3. OpenStack导入镜像后Launch不起来的几个问题

    Dashboard上显示state为error 没有其他报错 用nova list找到虚拟机的id 然后nova show,可以得到fault详细信息 也可以查看下面两个log /var/log/no ...

  4. ListView下拉刷新及上拉更多两种状态

    一.前言: 很多应用都会用到ListView,当然如果是iOS就会用UITableViewController,这两个控件在不同的OS上,功能是一样的,只是有些细微的不同(iOS的UITableVie ...

  5. VMware Workstation9安装Mac OS X10.9系统

    链接地址:http://jingyan.baidu.com/article/aa6a2c142cef740d4c19c426.html VMware Workstation9.0安装Mac OS X1 ...

  6. PHP面向对象基础实例

    <?phpclass marine{ public $blood = 50; //剩余的血 public $kills = 0; //杀敌数量 static $all_num = 0;//兵的数 ...

  7. int *p = NULL 和 *p = NULL(转载)

    int *p = NULL 和 *p = NULL int *p = NULL;      这时候我们用编译器查看p的值为0x00000000.这句话的意思是定义一个指针变量p,其指向内存里面保存的是 ...

  8. USACO Palindromic Squares 【STL__string_的应用】

    这里有个讲解 string 用法非常详细的博文:https://www.byvoid.com/zhs/blog/cpp-string 题目意思很简单啦,就是找回文 使用string可以高速A过 Sou ...

  9. Week7(10月21日)

    Part I:提问  =========================== 1.请为下图编写视图代码,视图中表单提交后,交给当前控制器和动作处理. 2.如何实现点击列标题排序功能? 3.分页时采用了 ...

  10. nice Validator参考

    快速上手 例1. DOM传参 1. 要验证一个表单,只需要给字段绑定规则“data-rule”就可以了2. 字段可以有多条规则,规则之间用分号(;)分隔3. js初始化不是必要的,只要是字段并且带有“ ...