技术回归01-Windows内存分配工具
很久没有写技术方面的东西了,这半年主要是在学习别人的东西,对自己提高比较大,算是一次技术回笼吧,这次学习之旅目的是结束技术方面的专注,开始向应用方面找突破口,也就是完成技术积累或者为技术的积累做坚实的准备。
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* _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重写:
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:
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内存分配工具的更多相关文章
- 01 Java 内存分配全面浅析
http://blog.csdn.net/shimiso/article/details/8595564 Java 内存分配全面浅析 本文将由浅入深详细介绍Java内存分配的原理,以帮助新手更轻松的 ...
- windows 内存分配回收检查工具
LeakDiag是微软一款检测memory leak的工具,使用比较简单 首先去下载一个ftp://ftp.microsoft.com/PSS/Tools/Developer%20Support%20 ...
- 【java虚拟机序列】java中的垃圾回收与内存分配策略
在[java虚拟机系列]java虚拟机系列之JVM总述中我们已经详细讲解过java中的内存模型,了解了关于JVM中内存管理的基本知识,接下来本博客将带领大家了解java中的垃圾回收与内存分配策略. 垃 ...
- 内存分配详解 malloc, new, HeapAlloc, VirtualAlloc,GlobalAlloc
很多地方都会使用内存,内存使用过程中操作不当就容易崩溃,无法运行程序,上网Google学习一下,了解整理下他们之间的区别以及使用 ,获益匪浅 0x01 各自的定义和理解 (1)先看GlobalAllo ...
- Netty 中的内存分配浅析-数据容器
本篇接续前一篇继续讲 Netty 中的内存分配.上一篇 先简单做一下回顾: Netty 为了更高效的管理内存,自己实现了一套内存管理的逻辑,借鉴 jemalloc 的思想实现了一套池化内存管理的思路: ...
- C++ Primer 学习笔记_98_特殊的工具和技术 --优化内存分配
特殊的工具和技术 --优化内存分配 引言: C++的内存分配是一种类型化操作:new为特定类型分配内存,并在新分配的内存中构造该类型的一个对象.new表达式自己主动执行合适的构造函数来初始化每一个动态 ...
- 全面介绍Windows内存管理机制及C++内存分配实例(四):内存映射文件
本文背景: 在编程中,很多Windows或C++的内存函数不知道有什么区别,更别谈有效使用:根本的原因是,没有清楚的理解操作系统的内存管理机制,本文企图通过简单的总结描述,结合实例来阐明这个机制. 本 ...
- 全面介绍Windows内存管理机制及C++内存分配实例
转自:http://blog.csdn.net/yeming81/article/details/2046193 本文基本上是windows via c/c++上的内容,笔记做得不错.. 本文背景: ...
- 解决Windows内存问题的两个小工具RamMap和VMMap(这个更牛更好)
来源:http://www.cr173.com/html/13006_1.html .net程序内存监测分配工具(CLR Profiler for .NET Framework 4)官方安装版 类型: ...
随机推荐
- Going Home(最大匹配km算法)
Going Home Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 20115 Accepted: 10189 Desc ...
- UVALive 5102 Fermat Point in Quadrangle 极角排序+找距离二维坐标4个点近期的点
题目链接:点击打开链接 题意: 给定二维坐标上的4个点 问: 找一个点使得这个点距离4个点的距离和最小 输出距离和. 思路: 若4个点不是凸4边形.则一定是端点最优. 否则就是2条对角线的交点最优,能 ...
- 在CTime类中重载<<和>>
程序代码: #include <iostream> using namespace std; class CTime//时间类 { private: unsigned short int ...
- B - 最大报销额
注意超时问题,一个题可能有很多种方法解决,但是想到解决方法的同时一定要考虑这个方法的复杂度,特别是对于acm的题,有可能出现超时的情况,很浪费时间 正式比赛中就很遗憾,血的教训. 下面贴上超时的代码并 ...
- list,map的疑问
代码: package com.wyl; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator ...
- web.xml的配置问题
[转]http://perfy315.iteye.com/blog/2009258 首先 classpath是指 WEB-INF文件夹下的classes目录 ,指的就是java文件编译之后的path. ...
- 为什么国内的网盘公司都在 TB 的级别上竞争,成本会不会太高?(还有好多其它回复)
作者:杜鑫链接:http://www.zhihu.com/question/21591490/answer/18762821来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处 ...
- 界面控件 - 滚动条ScrollBar(对滚动条消息和鼠标消息结合讲的不错)
界面是人机交互的门户,对产品至关重要.在界面开发中只有想不到没有做不到的,有好的想法,当然要尝试着做出来.对滚动条的扩展,现在有很多类是的例子. VS2015的代码编辑是非常强大的,其中有一个功能可以 ...
- 一步一步重写 CodeIgniter 框架 (10) —— 使用 CodeIgniter 类库(续)
上一节简单实现了 CI 的类库扩展模型,所以 _ci_load_class 和 _ci_init_class 写的不是很完备.根据上节课的分析,当 system/libraries 目录下存在 Ema ...
- ASP.NET过滤器的应用
在J2EE Web开发中有过滤器filter,该filter可以对指定的URL访问进行拦截,并执行过滤器的方法,根据实际应用情况,在过滤器中修改请求的代码.判断会话信息,也可以做权限控制,总之这个过滤 ...