内存泄漏工具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 ...
随机推荐
- 使用react-native做一个简单的应用-03欢迎界面
Android和iOS的欢迎界面是不一样的,在iOS中有一个默认的欢迎界面,而Android则需要自己写.因此我就分开说一下这两个平台的欢迎界面的搭建.下面先看一下实现效果: Android: iOS ...
- React-Native ListView加载图片淡入淡出效果的组件
今天练习项目中需要给listview在加载图片时增加一个淡入淡出的效果,因此干脆就自己封装了一个组件: 'use strict' import React from 'react-native' va ...
- JQ 更改li 颜色
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 设计模式之桥接模式(Bridge)--结构模型
1.意图 将抽象部分与它的实现部分分离,使它们可以独立地变化. 2.适用性 你不希望在抽象和它的实现部分之间有一个固定的绑定关系. 类的抽象与它的实现都应该可以通过子类的方式加以扩展. 抽象部分与实现 ...
- android的数据存储方式
数据存储在开发中是使用最频繁的,在这里主要介绍Android平台中实现数据存储的5种方式,分别是: 1 使用SharedPreferences存储数据 2 文件存储数据 3 SQLite数据库存储数据 ...
- netbeans ide怎么添加yii代码提示
菜单栏选择工具->选项->php界面里的全局包含路径中选择framework这个文件夹就可以了
- psacct监视用户执行的命令,如cpu时间和内存战胜,实时进程记账
psacct监视用户执行的命令,如cpu时间和内存战胜,实时进程记账
- mfc subclasswindow attach setwindowlong使用区别
1. CWnd::Attach BOOL Attach( HWND hWndNew ); 返回值:如果成功,则返回非零值:否则返回0. 参数: hWndNew 指定了Windows窗口的句柄. 说明: ...
- MVC与WebForm最大的区别
原文地址:http://www.cnblogs.com/birdshover/archive/2009/08/24/1552614.html 使用ASP.NET MVC框架,创建默认项目,第一直观感觉 ...
- 从txt中读入数据到数组中(fscanf)
C-sources: #include<stdio.h> int main() { FILE* fp; //定义一个文件 fp = fopen("p5.txt",&qu ...