从.NET程序中获取全局根

时间:2010-10-09 22:12:22

标签: c# .net f# profiling ants

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

此工具如何获取该信息?

2 个答案:

答案 0 :(得分:17)

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

您可以通过编写在您定位的流程中运行的CLR分析器来完成此操作。 CLR分析器是在设置COR_PROFILERCOR_PROFILING_ENABLED环境变量时由运行时实例化的C ++ COM对象(请参阅here)。有两个主要CLR profiling interfaces,具体而言,ICorProfilerCallbackICorProfilerInfoICorProfilerCallback是CLR用于通知您有关您订阅的特定事件(模块加载,函数JIT补充,线程创建,GC事件)的内容,而您的探查器可以使用ICorProfilerInfo来获取其他事件有关已加载程序集的线程,模块,类型,方法和元数据的信息。此接口是可以用于获取有关已分配类型的符号信息的接口。

使用您的探查器进行处理,您可以通过ICorProfilerInfo::ForceGC强制执行GC。 GC完成后,您的探查器将通过ICorProfilerCallback2::GarbageCollectionFinished收到通知,您将通过ICorProfilerCallback2::RootReferences2获得根引用。将根参考信息与ICorProfilerCallback::ObjectReferences组合在一起时,可以获得.NET应用程序的完整对象参考图。

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

为了激活上面提到的回调,您需要告诉您对它们感兴趣的CLR概要分析API。您可以在调用ICorProfilingInfo::SetEventMask时将COR_PRF_MONITOR_GCCOR_PRF_MONITOR_OBJECT_ALLOCATED指定为事件标记的一部分来执行此操作。

David Broman是CLR分析器的开发人员,his blog提供了大量有关分析的重要信息,包括您可能遇到的所有疯狂陷阱和问题。

答案 1 :(得分:3)

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

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

最后一点:不能从C#和VB.NET等托管代码中使用API​​。它只能从非托管代码中获得,例如C或C ++。因此,例如,C#app无法使用此API来检查自己的行为和对象。