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. BeeswaxException 以及其他问题

    Could not read table BeeswaxException(handle=QueryHandle(log_context='ae18ae74-518f-400b-b4b0-d399ed ...

  2. JQ 操作样式,单选按钮跟复选框

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  3. locate: can not stat () `/var/lib/mlocate/mlocate.db': No such file or directory

    安装好CentOS后,第一次进入系统使用locate命令,结果出现:locate: can not stat () `/var/lib/mlocate/mlocate.db': No such fil ...

  4. Sql中的Exists和in

    最近学习数据库的分页算法,提到第一种 SELECT TOP 页大小 *FROM table1WHERE id NOT IN          (          SELECT TOP 页大小*(页数 ...

  5. java static关键字

    方便在没有创建对象的情况下来进行调用(方法/变量). 很显然,被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问. static可以用来修饰类的 ...

  6. Router和History (路由控制)-backbone

    Router和History (路由控制) Backbone.Router担任了一部分Controller(控制器)的工作,它一般运行在单页应用中,能将特定的URL或锚点规则绑定到一个指定的方法(后文 ...

  7. 基于Cookie跨域的单点登录问题

    由于项目中,需要用的单点登录,主要的思路是:系统1:用户名密码-->写入Cookie-->其他系统读取Cookie. 1.在同一个服务器下的Cookie共享 @Component(&quo ...

  8. break语句的使用

    先举一个简单点的例子 #include<stdio.h> #include<stdlib.h> int main() { float a,b; char c; printf(& ...

  9. SQL Server 创建索引的 5 种方法

    前期准备: create table Employee (            ID int not null primary key,            Name nvarchar(4),  ...

  10. DataGridView添加复选框并向其中绑定值

    //DataGridview绑定数据 public void DataGridViewBandingData() { string year = this.CMB_year.SelectedValue ...