简单的Memory leak跟踪(三) 方案2:Dbghelp

dbghelp这个方案比较复杂,速度也比较慢,不过用在Trace的场合也不算太糟糕。

原理是,dbghelp.lib、dbghelp.h提供了一大堆获取当前调用栈信息(ESP、EBP),并通过这些调用栈,配合上相应模块的pdb文件,得出当前的调用模块(dll)、调用函数、调用行和指令。

具体的原理就不再废话了,网上dbghelp的使用方面的文档也很多,贴几个参考:

HOWTO: Dump Call Stack

一个调试器的实现(五)调试符号

使用DbgHelp获取函数调用堆栈之inline assembly(内联汇编)法


谈一下实现的原理:

还是截获new,但不需要提供new的特殊版本了,劫持全局new即可。

每次new之后,使用dbghelp功能来获取当前Call Stack,并剔除掉从new到Tracer的这几级Stack(就把最上面几个Stack扔掉就行,具体扔掉几个,根据实现不同而不同,我的实现从new开始Call了三层,所以扔掉3层即可,具体的可以大家自己来)。

建立一个hash,key仍然是分配的内存地址,value这里,有个优化的方案。因为CallStack比较大,如果要每次都存当前的CallStack,Tracer最后占的内存就太多了。但注意一点,new虽然在一个程序中能调用成百万上千万次,但new所在的地方,所可能出现的Call Stack的数量却是有限的,可能撑死也就千、万这个数量级。所以,Call Stack一旦获取后,我们可以先将Call Stack,缓存到一个Vector里,并算出CRC放到另一个map里。然后,hash的value只要保存当前Call Stack ID即可。

下次获取Callstack后,先算CRC到map中查一查,如果已经有相应的Call Stack了,就用相应的Call Stack即可,否则再生成新的,这样空间就得到优化了。

其他的跟之前那个Tracer一样,delete时,从Tracer表中去掉相应地址的记录。程序结束后,看hash是否清空,没清空就dump即可。

dump时还需要使用dbghelp功能。


因为这种实现需要劫持C++原始的void* operator new(size_t InSize),所以,需要像上一章那样说的,所有的hash、vector都需要用我们自己提供的、取消了Tracer功能的allocator。traceMalloc的实现的过程中如果有其他对operator new和new的调用,也需要一并消灭掉。


dbghelp这部分本身理解不是特别透彻,就不乱发表意见了,稍后发出代码,请轻喷~。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值