如何跨DLL边界跟踪内存

时间:2012-07-06 00:06:41

标签: c++ malloc new-operator delete-operator

我想要高性能的运行时内存指标,所以我写了一个基于重载new&的内存跟踪器。 delete。它基本上让你在堆中分配你的分配并分析它们的一切 - 碎片,大小,时间,数量,callstack等。但是,它有2个致命的缺陷:它无法跟踪在其他DLL中分配的内存以及何时拥有对象被传递给DLL,反之亦然。还有一些较小的缺陷:如果用户使用的是malloc而不是new,那么它就是未跟踪的;或者如果用户定义了一个类new / delete

如何消除这些缺陷?我认为我必须通过重载new / delete从根本上解决这个问题,还有更好的方法吗?

3 个答案:

答案 0 :(得分:4)

实现此目的的正确方法是使用绕道和在其自己的过程中运行的单独工具。程序大致如下:

  1. 在远程进程中创建内存分配。
  2. 放置一个装载你的dll的小型加载器的代码。
  3. 调用将运行您的加载程序的CreateRemoteThread API。
  4. 从加载的dll内部在alloc / dealloc函数上建立绕道(钩子,拦截器)。
  5. 处理电话,跟踪活动。
  6. 如果以这种方式实现工具,那么从DLL或直接从exe调用内存分配例程将是不重要的。此外,您可以跟踪任何流程中的活动,不一定是您自己编译的。

    MS Windows允许检查远程进程的虚拟地址空间的内容。您可以在直方图中总结使用以这种方式收集的虚拟地址空间,如下所示:

    enter image description here

    从这张图片中,您可以看到目标流程中存在多少大小的虚拟分配。

    enter image description here

    上图显示了32位MSVC DevEnv中虚拟地址空间使用情况的概述。蓝色条纹意味着提交的emory,洋红色条纹 - 保留。绿色是地址空间中未被占用的部分。

    您可以看到较低的地址非常分散,而中间区域则不是。高地址处的蓝线 - 加载到流程中的各种dll。

答案 1 :(得分:0)

您应该找到由new / deletemalloc / free调用的常见内存管理例程,并拦截这些例程。最后通常是malloc / free,但请检查以确保。

在UNIX上,我会将LD_PRELOAD与一些重新实现这些例程的库一起使用。在Windows上,您必须进行一些修改,但this link似乎可以很好地描述该过程。它基本上建议您使用Detours from Microsoft Research

答案 2 :(得分:0)

在模块之间传递对象的所有权从根本上是有缺陷的。它出现了你的自定义分配器,但还有很多其他情况也会失败:

  • 编译器升级,并仅重新编译一些DLL
  • 混合来自不同供应商的编译器
  • 静态链接运行时库

仅举几例。释放分配它的同一模块中的每个对象(通常通过导出删除函数,例如IUnknown::Release())。