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

该工具如何掌握这些信息?

最佳答案

(完全公开:我是Visual Studio Profiler团队的成员,但以下信息是公开的)

您可以通过编写在目标过程中运行的CLR分析器来实现。 CLR分析器是C ++ COM对象,当设置COR_PROFILERCOR_PROFILING_ENABLED环境变量时,运行时将实例化这些C ++ COM对象(请参见here)。主要有两个CLR profiling interfaces,分别是ICorProfilerCallbackICorProfilerInfoICorProfilerCallback是CLR用来通知您的特定事件(模块加载,函数JIT编译,线程创建,GC事件),而Profiler可以使用ICorProfilerInfo来获取有关线程的其他信息,加载的程序集的模块,类型,方法和元数据。您可以使用此接口来获取有关分配的类型的符号信息。

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

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

为了激活上述回调,您需要告知CLR分析API您对它们感兴趣。您可以通过在调用COR_PRF_MONITOR_GC时将COR_PRF_MONITOR_OBJECT_ALLOCATEDICorProfilingInfo::SetEventMask指定为事件标志的一部分来实现。

David Broman是CLR分析器的开发人员,并且his blog拥有大量有关概要分析的大量信息,其中包括所有可能遇到的疯狂陷阱和问题。

10-05 18:42
查看更多