从 .NET 程序获取全局根
我最近开始使用 ANTS 分析工具进行生产工作。除了对它们的强大感到惊讶之外,我忍不住想知道它们是如何工作的。例如,最有用的功能之一可以让您可视化正在运行的程序的全局根,以及对不同类型值的引用数量。
这个工具如何获取这些信息?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
我最近开始使用 ANTS 分析工具进行生产工作。除了对它们的强大感到惊讶之外,我忍不住想知道它们是如何工作的。例如,最有用的功能之一可以让您可视化正在运行的程序的全局根,以及对不同类型值的引用数量。
这个工具如何获取这些信息?
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(2)
(全面披露:我是 Visual Studio Profiler 团队的成员,但以下信息是公开的)
您可以通过编写在您的目标进程内运行的 CLR 分析器来完成此操作。 CLR 探查器是 C++ COM 对象,当设置 COR_PROFILER 和 COR_PROFILING_ENABLED 环境变量时,运行时会实例化这些对象(请参阅com/en-us/library/bb384689.aspx" rel="nofollow noreferrer">此处)。有两个主要的 CLR 分析接口,具体来说,
ICorProfilerCallback
和ICorProfilerInfo
。ICorProfilerCallback
是 CLR 用于通知您订阅的特定事件(模块加载、函数 JIT 编译、线程创建、GC 事件)的方法,同时可以使用ICorProfilerInfo
通过探查器获取有关已加载程序集的线程、模块、类型、方法和元数据的附加信息。您可以使用此接口来获取有关分配的类型的符号信息。在分析器处于进程中时,您可以通过
ICorProfilerInfo 强制执行 GC: :ForceGC
。 GC 完成后,您的探查器将通过ICorProfilerCallback2::GarbageCollectionFinished 收到通知
,您将通过 < 获取根引用代码>ICorProfilerCallback2::RootReferences2。当您将根引用信息与ICorProfilerCallback::ObjectReferences
,您可以获得.NET应用程序的完整对象引用图。您可以使用
ICorProfilerCallback::ObjectAlowned
回调来确定何时创建各个 CLR 对象。不过,这可能会很昂贵,因为您至少要为每个分配的对象进行一次额外的函数调用。您可以通过将 CLR 分配的
ObjectID
映射到您自己的内部 ID 来跟踪各个对象。给定对象的ObjectID
是一个临时指针,因为它可能会随着垃圾收集的发生而改变,这可能会导致对象在压缩期间移动。 此处对此过程进行了说明。您可以使用ICorProfilerCallback::MovedReferences
< 中的信息/a> 跟踪移动物体。为了激活上面提到的回调,您需要告诉 CLR 分析 API 您对它们感兴趣。您可以通过在调用
ICorProfilingInfo::SetEventMask
。David Broman 是 CLR 分析器的开发人员,他的博客提供了大量有关概要分析的重要信息,包括您可能遇到的所有疯狂陷阱和问题。
(Full disclosure: I'm on the Visual Studio Profiler team, but the below information is public)
You can do this by writing a CLR profiler that runs inside the process you're targeting. CLR profilers are C++ COM objects that get instantiated by the runtime when the
COR_PROFILER
andCOR_PROFILING_ENABLED
environment variables are set (see here). There are two main CLR profiling interfaces, specifically,ICorProfilerCallback
andICorProfilerInfo
.ICorProfilerCallback
is what the CLR uses to notify you about specific events that you subscribe to (module loads, function JIT compliation, thread creation, GC events), whileICorProfilerInfo
can be used by your profiler to obtain additional information about threads, modules, types, methods, and metadata for the loaded assemblies. This interface is what you could use to obtain symbol information about the types allocated.With your profiler in-process, you can force a GC through
ICorProfilerInfo::ForceGC
. After the GC completes, your profiler will get notified viaICorProfilerCallback2::GarbageCollectionFinished
, and you will get the root references viaICorProfilerCallback2::RootReferences2
. When you combine the root reference information withICorProfilerCallback::ObjectReferences
, you can get the complete object reference graph for your .NET application.You can get more realtime information by using the
ICorProfilerCallback::ObjectAllocated
callback to determine when individual CLR objects get created. This can be expensive, though, since you're incurring at least an additional function call for each allocated object. You can track individual objects by mapping the CLR-assignedObjectID
to your own internal ID. AnObjectID
for a given object is an ephemeral pointer since it can change as garbage collections happen, which can cause objects to move during compaction. This process is illustrated here. You can use the information fromICorProfilerCallback::MovedReferences
to track moving objects.In order to activate the callbacks mentioned above, you need to tell the CLR profiling API that you're interested in them. You can do this by specifying
COR_PRF_MONITOR_GC
andCOR_PRF_MONITOR_OBJECT_ALLOCATED
as part of your event flags when callingICorProfilingInfo::SetEventMask
.David Broman is the developer on the CLR profiler, and his blog has tons of great information on profiling in general, including all the crazy pitfalls and issues you might run into.
像 ANTS 这样的分析器使用 CLR 本身提供的“分析 API”,它可以很简单地告诉您 CLR 内部发生了什么。例如,有一个 API 回调方法在分配对象时发生,恰当地命名为 对象分配()。同样,当进入方法、创建线程等时也会发生事件。
原始的分析 API 称为 ICorProfilerCallback。更高版本称为 CoreProfilerCallback2 和 CoreProfilerCallback3。如果你用谷歌搜索这些名字,你就会找到你正在寻找的答案。在 codeproject 上,您可以看到一个实际示例:创建自定义 .NET Profiler
注意:该 API 不能从 C# 和 VB.NET 等托管代码中使用。它只能从非托管代码(例如 C 或 C++)中获得。例如,C# 应用程序无法使用此 API 来检查其自身的行为和对象。
Profilers like ANTS use an "profiling API" presented by the CLR itself, that quite simply can tell you what goes on inside the CLR. For instance there is an API callback-method that occur when an object is allocated, aptly named ObjectAllocated(). Likewise there are events for when methods are entered, when threads are created, etc etc.
The original profiling API is called ICorProfilerCallback. Later versions are called CoreProfilerCallback2 and CoreProfilerCallback3. If you google those names you'll find exactly the answers you're looking for. On codeproject you can see a practical example: Creating a Custom .NET Profiler
A final note: The API cannot be used from managed code like C# and VB.NET. It's only available from unmanaged code like e.g. C or C++. So a C# app cannot use this API to examine its own behavior and objects, for instance.