内存泄漏工具VLD1.0_要点分析
0X01 关闭FPO优化
|
// Frame pointer omission (FPO) optimization should be turned off for this // entire file. The release VLD libs don't include FPO debug information, so FPO // optimization will interfere with stack walking. #pragma optimize ("y", off) |
Release版本的VLD库不包含FPO调试信息,进而影响栈回溯,所以文件开头关闭FPO优化;
0X02 内存泄漏检测器全局对象
|
// The one and only VisualLeakDetector object instance. This is placed in the // "compiler" initialization area, so that it gets constructed during C runtime // initialization and before any user global objects are constructed. Also, // disable the warning about us using the "compiler" initialization area. #pragma warning (disable:4074) #pragma init_seg (compiler) VisualLeakDetector visualleakdetector; |
对于同一个文件来说,全局变量的构造顺序是按照全局变量的声明顺序来构造的。但对于不同文件来说,不同文件间的全局变量构造顺序是不确定的。在C++标准中,只要求“处于同一编译但与的全局对象按其声明顺序初始化并倒序析构”,但并没有对处于不同编译单元的全局对象的初始化顺序做出要求。
通过init_seg预处理器指令中,:
|
#pragma init_seg(compiler) #pragma init_seg(lib) #pragma init_seg(user) #pragma init_seg("user_defined_segment_name") |
编译器、库、用户和用户定义段,按顺序依次初始化(但据实测,用户和用户定义段的优先级相同);
注:一个源文件中只能出现一次init_seg指令;且编译器段是微软保留给C/C++运行时库用的,一般情况下我们不应该使用它。
VLD为了保证尽可能的全面诊断内存泄漏,势必需要在其他全局变量构造前完成初始化。VLD就利用init_seg了处理器指令,让VLD的VisualLeakDetector在绝大多数情况下早于其他全局变量进行构造和初始化,即上面的实现。
#pragma warning (disable:4074):用于屏蔽C4074编译器警告,否则编译时会提示:warning C4074: initializers put in compiler reserved initialization area
0X03 设置内存开辟钩子
|
VisualLeakDetector::VisualLeakDetector () { 。。。 。。。 else if (linkdebughelplibrary()) { // 显示加载dbghelp.dll中必要的API // Register our allocation hook function with the debug heap. m_poldhook = _CrtSetAllocHook(allochook); report("Visual Leak Detector Version "VLD_VERSION" installed ("VLD_LIBTYPE").\n"); reportconfig(); 。。。 。。。 } } |
0x04 钩子函数
|
// 该函数不用考虑线程安全问题,CRT有调试堆有锁定 int VisualLeakDetector::allochook (int type, void *pdata, size_t size, int use, long request, const unsigned char *file, int line) { static bool inallochook = false; int status = true; // 1. 防止递归;2.不处理CRT内部使用的内存块 if (inallochook || (use == _CRT_BLOCK)) { if (visualleakdetector.m_poldhook) { status = visualleakdetector.m_poldhook(type, pdata, size, use, request, file, line); } return status; } inallochook = true; // Call the appropriate handler for the type of operation. switch (type) { case _HOOK_ALLOC: visualleakdetector.hookmalloc(request); break; case _HOOK_FREE: visualleakdetector.hookfree(pdata); break; case _HOOK_REALLOC: visualleakdetector.hookrealloc(pdata, request); break; default: visualleakdetector.report("WARNING: Visual Leak Detector: in allochook(): Unhandled allocation type (%d).\n", type); break; } if (visualleakdetector.m_poldhook) { status = visualleakdetector.m_poldhook(type, pdata, size, use, request, file, line); } inallochook = false; return status; } |
0X05 栈回溯
|
#if defined(_M_IX86) || defined(_M_X64) #pragma auto_inline(off) DWORD_PTR VisualLeakDetector::getprogramcounterx86x64 () { DWORD_PTR programcounter; // Get the return address out of the current stack frame __asm mov AXREG, [BPREG + SIZEOFPTR] // Put the return address into the variable we'll return __asm mov [programcounter], AXREG return programcounter; } #pragma auto_inline(on) #endif // defined(_M_IX86) || defined(_M_X64) void VisualLeakDetector::getstacktrace (CallStack *callstack) { DWORD architecture; CONTEXT context; unsigned int count = 0; STACKFRAME64 frame; DWORD_PTR framepointer; DWORD_PTR programcounter; // Get the required values for initialization of the STACKFRAME64 structure // to be passed to StackWalk64(). Required fields are AddrPC and AddrFrame. #if defined(_M_IX86) || defined(_M_X64) architecture = X86X64ARCHITECTURE; programcounter = getprogramcounterx86x64(); __asm mov [framepointer], BPREG // Get the frame pointer (aka base pointer) #else // If you want to retarget Visual Leak Detector to another processor // architecture then you'll need to provide architecture-specific code to // retrieve the current frame pointer and program counter in order to initialize // the STACKFRAME64 structure below. #error "Visual Leak Detector is not supported on this architecture." #endif // defined(_M_IX86) || defined(_M_X64) // Initialize the STACKFRAME64 structure. memset(&frame, 0x0, sizeof(frame)); frame.AddrPC.Offset = programcounter; frame.AddrPC.Mode = AddrModeFlat; frame.AddrFrame.Offset = framepointer; frame.AddrFrame.Mode = AddrModeFlat; // Walk the stack. while (count < _VLD_maxtraceframes) { count++; if (!pStackWalk64(architecture, m_process, m_thread, &frame, &context, NULL, pSymFunctionTableAccess64, pSymGetModuleBase64, NULL)) { // Couldn't trace back through any more frames. break; } if (frame.AddrFrame.Offset == 0) { // End of stack. break; } // Push this frame's program counter onto the provided CallStack. callstack->push_back((DWORD_PTR)frame.AddrPC.Offset); } } |
StackWalk64进行栈回溯需要精确的知道栈从哪里开始。这需要提供当前的栈帧地址和当前的EIP(RIP)寄存器值,而通过GetThreadContext获取的当前线程上下文对于一个正在运行的线程是不可靠的。所以这里通过了内联汇编代码实现,即getprogramcounterx86x64()函数的作用,其返回函数的返回地址,当函数返回时即当前的EIP(RIP)寄存器值。
内存泄漏工具VLD1.0_要点分析的更多相关文章
- VS2015 定位内存泄漏工具vld
介绍一款在vs2015开发环境定位内存泄漏工具:Visual Leak Detector ,具体的使用方法如下: 1. 安装vld-2.5-setup.exe (下载链接地址后面会给出),安装过程会 ...
- 【腾讯优测干货分享】Android内存泄漏的简单检查与分析方法
本文来自于Dev Club 开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57d14047603a5bf1242ad01b 导语 内存泄漏问题大约是An ...
- Linux下内存泄漏工具【转】
转自:http://www.cnblogs.com/guochaoxxl/p/6970090.html 概述 内存泄漏(memory leak)指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况 ...
- Linux下内存泄漏工具
概述 内存泄漏(memory leak)指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况,在大型的.复杂的应用程序中,内存泄漏是常见的问题.当以前分配的一片内存不再需要使用或无法访问时,但是却 ...
- js的内存泄漏场景、监控以及分析
内存泄漏 Q:什么是内存泄漏? 字面上的意思,申请的内存没有及时回收掉,被泄漏了 Q:为什么会发生内存泄漏? 虽然前端有垃圾回收机制,但当某块无用的内存,却无法被垃圾回收机制认为是垃圾时,也就发生内存 ...
- Valgrind 内存泄漏工具
Valgrind 是一款 Linux下(支持 x86.x86_64和ppc32)程序的内存调试工具,它可以对编译后的二进制程序进行内存使用监测(C语言中的malloc和free,以及C++中的new和 ...
- malloc钩子和内存泄漏工具mtrace、Valgrind
一:malloc钩子函数 static void* (* old_malloc_hook) (size_t,const void *);static void (* old_free_hook)(vo ...
- 安卓 内存 泄漏 工具 LeakCanary 使用
韩梦飞沙 yue31313 韩亚飞 han_meng_fei_sha 313134555@qq.com LeakCanary是Square开源了一个内存泄露自动探测神器 .这是项目的github仓库地 ...
- Logcat中报内存泄漏MemoryLeak的一次分析
有时候运行APP的时候Logcat中会报错,提示资源没有释放,Memory leak, 于是打开Android Studio在Android Monitor工具栏点开,有Logcat和Monitors ...
随机推荐
- HDU 2157 - How many ways??
给图,图中任意可达的两点间步数为1 问从图中A点走到B点步数为k的有几条路 祭出离散数学图论那章中的 邻接矩阵A. 设S=Ak 则 S[a][b] 为 a到b,步数为k的不同路的条数 剩下的就是矩阵快 ...
- 2015.4.16-SQL-内连接与外连接
1.内连接 如图: 关键字 inner join 2.外连接 分为左外连接 和右外连接,即如果是左外连接,即使左面没有值,也会显示为null, 右外连接也如此 关键字 left join ; righ ...
- ThinkPHP 类似Yii的Gii生成Model的功能。
ThinkPHP 类似Yii的Gii生成Model的功能.自动生成ThinkPhp 3.1 的基础模型.. #!/usr/bin/env php <?php /** * * THINKPHP 基 ...
- inflate, findViewById与setContentView的区别与联系
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentV ...
- .Net框架中,.ashx页面访问session
public class ClassName : System.Web.SessionState.IRequiresSessionState 需实现session接口
- FormSheet式模态视图,点击模态视图外隐藏模态视图的方法
@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...
- HDU1043 Eight(BFS)
Eight(South Central USA 1998) Time Limit:5000MS Memory Limit:32768KB 64bit IO Format:%I64d & ...
- Net Core WebApi单元测试
单元测试 本篇将结合这个系列的例子的基础上演示在Asp.Net Core里如何使用XUnit结合Moq进行单元测试,同时对整个项目进行集成测试. 第一部分.XUnit 修改 Project.json ...
- Rule Or WorkFlow
The main value of a Workflow engine is that it makes it possible to customize the flows through some ...
- Android ListView A~Z快速索引(改进版)
上一篇文章虽然实现了ListView 快速索引的效果,但是有一个小小的Bug.这个Bug我在前面也说了,这篇文章就来解决这个Bug. 我研究的时候发现只要showBg值为true,中间的字母就显示,而 ...