zoukankan      html  css  js  c++  java
  • Windbg找出managed对象memory leak的一种笨办法

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

    • 用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
    );



    更多阅读

    Capturing memory dumps for 32-bit processes on an x64 machine
    https://blogs.msdn.microsoft.com/tess/2010/09/29/capturing-memory-dumps-for-32-bit-processes-on-an-x64-machine/

    Correlating the output of !eeheap -gc and !address
    https://blogs.msdn.microsoft.com/maoni/2006/11/08/correlating-the-output-of-eeheap-gc-and-address/

    Debugging with the Right Tools
    https://blogs.msdn.microsoft.com/maoni/2010/04/23/debugging-with-the-right-tools/

  • 相关阅读:
    WinHex简介
    CTF中图片隐藏文件分离方法
    隐写术的相关解法
    JPEG文件格式
    PNG文件结构
    网络安全实验室—基础关
    实验吧—密码学(1)
    YIT-CTF—隐写术
    YIT-CTF—Web
    YIT-CTF—社工类
  • 原文地址:https://www.cnblogs.com/fbird/p/5889596.html
Copyright © 2011-2022 走看看