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_要点分析的更多相关文章

  1. VS2015 定位内存泄漏工具vld

    介绍一款在vs2015开发环境定位内存泄漏工具:Visual Leak Detector ,具体的使用方法如下: 1.  安装vld-2.5-setup.exe (下载链接地址后面会给出),安装过程会 ...

  2. 【腾讯优测干货分享】Android内存泄漏的简单检查与分析方法

    本文来自于Dev Club 开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57d14047603a5bf1242ad01b 导语 内存泄漏问题大约是An ...

  3. Linux下内存泄漏工具【转】

    转自:http://www.cnblogs.com/guochaoxxl/p/6970090.html 概述 内存泄漏(memory leak)指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况 ...

  4. Linux下内存泄漏工具

    概述 内存泄漏(memory leak)指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况,在大型的.复杂的应用程序中,内存泄漏是常见的问题.当以前分配的一片内存不再需要使用或无法访问时,但是却 ...

  5. js的内存泄漏场景、监控以及分析

    内存泄漏 Q:什么是内存泄漏? 字面上的意思,申请的内存没有及时回收掉,被泄漏了 Q:为什么会发生内存泄漏? 虽然前端有垃圾回收机制,但当某块无用的内存,却无法被垃圾回收机制认为是垃圾时,也就发生内存 ...

  6. Valgrind 内存泄漏工具

    Valgrind 是一款 Linux下(支持 x86.x86_64和ppc32)程序的内存调试工具,它可以对编译后的二进制程序进行内存使用监测(C语言中的malloc和free,以及C++中的new和 ...

  7. malloc钩子和内存泄漏工具mtrace、Valgrind

    一:malloc钩子函数 static void* (* old_malloc_hook) (size_t,const void *);static void (* old_free_hook)(vo ...

  8. 安卓 内存 泄漏 工具 LeakCanary 使用

    韩梦飞沙 yue31313 韩亚飞 han_meng_fei_sha 313134555@qq.com LeakCanary是Square开源了一个内存泄露自动探测神器 .这是项目的github仓库地 ...

  9. Logcat中报内存泄漏MemoryLeak的一次分析

    有时候运行APP的时候Logcat中会报错,提示资源没有释放,Memory leak, 于是打开Android Studio在Android Monitor工具栏点开,有Logcat和Monitors ...

随机推荐

  1. 动态加载Ribbon功能区

    上下文选项卡对新UI的功能提供了极大的推进作用.当用户对某对象执行特定的任务时就会出现特定的选项卡.例如,在Excel中处理图表时,一个上下文选项卡提供用于图表处理的额外选项.本文将介绍创建和执行这些 ...

  2. c++STL之sort排序

    排序算法为竞赛中最常用的算法之一,我们可以利用C++自带的库函数进行排序.                                                                ...

  3. vim自动补全文章搜集

    引用文章A:http://blog.csdn.net/wendy260310/article/details/18035555 文章介绍:添加C++标准库的tags文件方法.(中文版) 引用文章B:h ...

  4. MyEclipse破解方法

    Myeclipse 2014 破解补丁,首先需要先下载 Myeclipse 2014 官方安装文件,下载地址 http://www.jb51.net/softs/150886.html,然后下载此补丁 ...

  5. 关于cookie的使用

    cookie的属性 domain:域名,即cookie所能使用的范围,当然当前域下可以在当前域下cookie,还有一个就是该域名的父级域名(子级的域名下是可以访问父级域名下的cookie,父级域名是不 ...

  6. oracle 集合定义

    集合:是具有相同定义的元素的聚合.Oracle有两种类型的集合: 可变长数组(VARRAY):可以有任意数量的元素,但必须预先定义限制值. 嵌套表:视为表中之表,可以有任意数量的元素,不需要预先定义限 ...

  7. [转]IP地址-子网掩码-默认网关

    IP地址:是给每个连接在Internet上的主机分配的一个32bit地址.地址有两部分组成,一部分为网络地址,另一部分为主机地址.IP地址分为A.B.C.D.E 5类.常用的是B和C两类.网络地址的位 ...

  8. source install MacPorts--checking for Tcl configuration... configure: error: Can't find Tcl configuration definitions

    If you installed MacPorts using the package installer, skip this section. To install MacPorts from t ...

  9. jquery load(URL,FUNCTION(){}) 异步加载页面

    $("#btnSearch").click(function () { var queryUrl = '/Report/LoadInsClassifFileNew'; if ($( ...

  10. SemaphoreFullException when checking user role via ASP.NET membership

    将指定的计数添加到该信号量中会导致其超过最大计数 This issue was fixed by restarting ASP.NET Development Server on windows ta ...