3

我最近开始使用 ANTS 分析工具进行生产工作。除了对它们的出色表现感到惊讶之外,我不禁想知道它们是如何工作的。例如,最有用的功能之一是让您可视化正在运行的程序的全局根,其中包含对不同类型值的引用数量。

这个工具如何获取这些信息?

4

2 回答 2

17

(全面披露:我是 Visual Studio Profiler 团队的一员,但以下信息是公开的)

您可以通过编写一个在您所针对的进程内运行的 CLR 分析器来做到这一点。COR_PROFILERCLR 探查器是 C++ COM 对象,在设置和COR_PROFILING_ENABLED环境变量时由运行时实例化(请参见此处)。有两个主要的CLR 分析接口,具体来说,ICorProfilerCallbackICorProfilerInfo. ICorProfilerCallback是 CLR 用来通知您订阅的特定事件(模块加载、函数 JIT 编译、线程创建、GC 事件)的内容,而ICorProfilerInfo您的探查器可以使用它来获取有关线程、模块、类型、方法的其他信息,和已加载程序集的元数据。您可以使用此接口来获取有关已分配类型的符号信息。

在您的探查器进程中,您可以强制 GC 通过ICorProfilerInfo::ForceGC. GC 完成后,您的探查器将通过 收到通知ICorProfilerCallback2::GarbageCollectionFinished,您将通过 获取根引用ICorProfilerCallback2::RootReferences2。当您将根引用信息与 结合时ICorProfilerCallback::ObjectReferences,您可以获得 .NET 应用程序的完整对象引用图。

您可以通过使用ICorProfilerCallback::ObjectAllocated回调来确定何时创建单个 CLR 对象来获取更多实时信息。但是,这可能会很昂贵,因为您至少会为每个分配的对象产生一个额外的函数调用。ObjectID您可以通过将分配的 CLR 映射到您自己的内部 ID来跟踪单个对象。给定对象的anObjectID是一个临时指针,因为它可以随着垃圾收集的发生而改变,这可能导致对象在压缩期间移动。此处说明了此过程。您可以使用来自的信息ICorProfilerCallback::MovedReferences来跟踪移动对象。

为了激活上面提到的回调,您需要告诉 CLR 分析 API 您对它们感兴趣。您可以通过在调用 时指定COR_PRF_MONITOR_GCCOR_PRF_MONITOR_OBJECT_ALLOCATED作为事件标志的一部分来做到这一点ICorProfilingInfo::SetEventMask

David Broman 是 CLR 分析器的开发人员,他的博客包含大量关于一般分析的重要信息,包括您可能遇到的所有疯狂陷阱和问题。

于 2010-10-09T22:38:58.000 回答
3

像 ANTS 这样的分析器使用 CLR 本身提供的“分析 API”,它可以很简单地告诉您 CLR 内部发生了什么。例如,在分配对象时会发生一个 API 回调方法,恰当地命名为ObjectAllocated()。同样,当输入方法、创建线程等时也会发生事件。

原始分析 API 称为 ICorProfilerCallback。更高版本称为 CoreProfilerCallback2 和 CoreProfilerCallback3。如果你用谷歌搜索这些名字,你会找到你正在寻找的答案。在 codeproject 上,您可以看到一个实际示例:Creating a Custom .NET Profiler

最后一点:API 不能用于 C# 和 VB.NET 等托管代码。它仅适用于非托管代码,例如 C 或 C++。因此,例如,C# 应用程序不能使用此 API 来检查其自身的行为和对象。

于 2010-10-09T22:45:35.913 回答