4

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

我怎样才能消除这些缺陷?我认为我必须通过重载new/从根本上错误地解决这个问题delete,有没有更好的方法?

4

3 回答 3

4

实现这一点的正确方法是使用 detours 和在其自己的进程中运行的单独工具。流程大致如下:

  1. 在远程进程中创建内存分配。
  2. 将加载您的 dll 的小型加载程序的代码放在那里。
  3. 调用CreateRemoteThread将运行您的加载程序的 API。
  4. 从加载的 dll 内部在 alloc/dealloc 函数上建立绕行(钩子、拦截器)。
  5. 处理呼叫,跟踪活动。

如果您以这种方式实现您的工具,那么从哪个 DLL 或直接从 exe 调用内存分配例程并不重要。此外,您可以跟踪任何流程的活动,不一定是您自己编译的。

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

在此处输入图像描述

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

在此处输入图像描述

上图显示了 32 位 MSVC DevEnv 中虚拟地址空间使用情况的概览。蓝色条纹意味着一块承诺的埃默里,洋红色条纹 - 保留。绿色是地址空间中未被占用的部分。

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

于 2012-07-06T00:21:59.697 回答
0

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

在 UNIX 上,我会使用LD_PRELOAD一些重新实现这些例程的库。在 Windows 上,你必须稍微破解一下,但这个链接似乎很好地描述了这个过程。它基本上建议您使用Microsoft Research 的 Detours

于 2012-07-06T00:21:37.467 回答
0

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

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

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

于 2012-07-06T00:22:06.177 回答