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. canvas模糊事件处理

    不知道大家项目中有没有用到canvas时还有时候会出现模糊的情况: 具体推测可能是屏幕改变了,然而canvas的渲染对象并没有跟着一起变: 这里简单介绍个对象,window.devicePixelRa ...

  2. <httpRuntime>

    1.在webconfig中httpconfig属性只能出现一次 配置httpRunTime也可以让FileUpload上传更大的文件,不过设置太大了会因用户将大量文件传递到该服务器而导致的拒绝服务攻击 ...

  3. 如何在美国公司写project plan 邮件--以hadoop安装和Mahout数据分析为例子

    Hi, XXX (boss name) Project Title:  Hadoop installation and Data analysis based on Mahout Deliverabl ...

  4. css基础之 图片瀑布流布局:用CSS+DIV等宽格子堆砌瀑布流效果 (一)

    <!doctype html> <html> <head> <meta charset="UTF-8"/> <title> ...

  5. 为什么JavaScript函数中的参数前面不能加var

    首先这里是JavaScript的语法规则. 其次在调用function()函数的时候参数时外部传入的.在传入之前就已经被声明了.没必要在函数参数里声明. 如果想要在函数里用新的参数 function( ...

  6. IE10以下placeholder不兼容

    做页面的时候在谷歌中是显示的,但是换了IE之后总是不显示,一个文本框还好,如果有多个的话,如图: 添加以下一段Jquery代码: <script> var JPlaceHolder = { ...

  7. RemoteViews的内部机制

    1.RemoteViews的构造方法public RemoteViews(String packageName,int layoutId) 第一个表示当前应用的包名(反射机制需要),第二个表示加载的布 ...

  8. 关于ajax发送的数据问题

    今天在做保存富文本编辑器的内容时,发送了一个ajax请求: $.ajax({ type:"POST", url:"{% url 'cms:add' %}", d ...

  9. QP在STM32F10X上第一个应用

        两天没有写博客了,这两天主要还是在考虑软件的结构性问题,用不用QP?用不用ST库函数?看了ucos,freertos,tinyos以及Contiki,库函数的问题看了使用库的软件结构,直接操作 ...

  10. Thinking in C++: 第1章 为什么C++会成功(改进了C的缺点,可复用C的知识与库,执行效率相当)

    本文内容摘抄自C++经典书籍:<Thinking in C++>   操作概念:OOP程序像什么 我们已经知道,用C 语言编写的过程程序就是一些数据定义和函数调用.要理解这种程序的含义,程 ...