Windbg找出memory leak的一种笨办法

Posted 任智康

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Windbg找出memory leak的一种笨办法相关的知识,希望对你有一定的参考价值。

  以下内容是转自 http://www.cnblogs.com/fbird/p/5889596.html

  以前做项目碰到过一个问题,在客户的站点上面发现有严重的内存泄漏。幸运的是我们找到了重现的步骤,一轮下来大概有几十兆的泄漏,但是以下常规方法却没啥用。

  • 用windbg把heap上面的object全部dump下来,和上一轮操作作比较,并不能发现什么有用的东西。
  • 大对象heap上面也没啥有用的东西。
  • 像.net memory profiler这种比较智能的工具也用不上,因为一轮操作下来已经能使工具out of memory。

  项目有几百万行代码,但是我们认为可能发生大内存泄漏的就几个点。把那几个点的代码都找了一遍,没有任何结果。左寻右找,终于找到了一种比较笨但是却很管用的方法。

1. 打开Windbg, attach进程。

2. 加载symbol

3. 打断点 (可以用.logopen c:\\memoryleak.txt把log记下来)

bp kernel32!virtualalloc ".printf\\"#alloc memory# %lu  \\\\n \\",dwo(esp+8);!clrstack;g;"

4. 输入g然后回车让进程继续跑。

5. 将重现步骤跑一遍,然后去review日志。

  接下来的过程比较笨,Review日志的过程中找到比较可疑的申请大块内存的点,注释代码,编译Assembly替换,看内存泄漏还在不在。最终还是找到了那个泄漏的地方,一个remoting的proxy,出了作用域但是其指向的内存去没有被自动释放。

解决这个问题的最关键的就是下面这条命令:
     bp kernel32!virtualalloc ".printf\\"#alloc memory# %lu  \\\\n \\",dwo(esp+8);!clrstack;g;"

  它的作用就是在kernel32的virtualalloc函数上面打断点,当该函数被执行到的时候,就把该函数申请的内存数量(在esp+8这个位置,dwo是把这个里面的值转成十进制),以及调用该函数的托管栈(clrstack)打印出来,然后让函数继续跑(g)。

  需要说明的是,这个命令仅对32位进程有效,因为根据32位cpu的calling convention,esp+4是第一个参数位置,esp+8是第二个,以此类推。64位的进程要去再查一下对应的calling convention看相关参数在哪个位置。

LPVOID WINAPI VirtualAlloc(
  _In_opt_ LPVOID lpAddress,
  _In_     SIZE_T dwSize,
  _In_     DWORD  flAllocationType,
  _In_     DWORD  flProtect
);

以上是关于Windbg找出memory leak的一种笨办法的主要内容,如果未能解决你的问题,请参考以下文章

Memory Leak检测神器--LeakCanary初探

Memory Leak检測神器--LeakCanary初探

Memory Leak检测神器--LeakCanary初探

Memory Leak检测神器--LeakCanary初探

b.Jre Memory Leak Prevention Listener

LINUX GDB: IDENTIFY MEMORY LEAKS(通过gdb脚本打印malloc和free)