更新:2007 年 11 月
探查器是一个监视另一应用程序的执行情况的工具。公共语言运行库 (CLR) 探查器是一个由函数组成的动态链接库 (DLL),这些函数通过使用分析 API 接收来自 CLR 的消息或将消息发送给 CLR。探查器 DLL 由 CLR 在运行时加载。
传统的分析工具主要用于测量应用程序的执行情况。也就是说,这些工具将测量花在每个函数上的时间或一段时间内应用程序的内存使用量。分析 API 针对较广泛的一类诊断工具,如代码覆盖率实用工具,甚至是高级调试辅助工具。这些工具的用途本质上都是为了进行诊断。分析 API 不仅测量而且还监视应用程序的执行情况。因此,应用程序本身决不应该使用分析 API,并且应用程序的执行情况不应该取决于探查器(或受其影响)。
与分析常规编译的机器码相比,分析 CLR 应用程序需要更多的支持。这是因为 CLR 引入了一些概念,例如应用程序域、垃圾回收、托管的异常处理、代码实时 (JIT) 编译(将 Microsoft 中间语言 (MSIL) 代码转换成本机代码)和类似功能。常规分析机制无法识别或提供有关这些功能的有用信息。分析 API 可以有效地提供此缺少的信息,并且对 CLR 和分析的应用程序的性能影响最小。
通过进行运行时 JIT 编译,可以很好地进行分析。通过使用分析 API,探查器在对内存中的 MSIL 代码流进行 JIT 编译之前可以为例程更改此代码流。通过这种方式,探查器可以向需要更深入调查的特定例程动态添加检测代码。虽然这种方法在一般情况下可行,但是对于 CLR 来说,使用分析 API 进行实现更加简单。
分析 API
通常,分析 API 用于编写“代码探查器”,代码探查器是一个监视托管应用程序执行情况的程序。
探查器 DLL 将使用此分析 API,前者将加载到与正在被分析的应用程序相同的进程中。此探查器 DLL 将实现一个回调接口(在 .NET Framework 1.0 和 1.1 版中为 ICorProfilerCallback,在 2.0 版中为 ICorProfilerCallback2)。CLR 将调用该接口中的方法来通知探查器有关分析进程中的事件的情况。通过使用 ICorProfilerInfo 和 ICorProfilerInfo2 接口中的方法获取有关分析应用程序状态的信息,此探查器可以回调到运行库中。
![]() |
---|
在与分析应用程序相同的进程中只应该运行探查器解决方案的数据收集部分。所有用户接口和数据分析都应该在单独的进程中执行。 |
下图演示探查器 DLL 如何与正在被分析的应用程序以及 CLR 进行交互。
分析体系结构
通知接口
ICorProfilerCallback 和 ICorProfilerCallback2 可被视为通知接口。这些接口由诸如 ClassLoadStarted、ClassLoadFinished 和 JITCompilationStarted 之类的方法组成。CLR 在每次执行加载或卸载类、编译函数等操作时,它将在探查器的 ICorProfilerCallback 或 ICorProfilerCallback2 接口中调用相应的方法。
例如,探查器可以通过以下两个通知函数来测量代码性能:FunctionEnter2 和 FunctionLeave2。它仅对每个通知加时间戳、累积结果并输出一个列表,该列表指出了在执行应用程序过程中耗用大部分 CPU 或时钟时间的函数。
信息检索接口
分析中涉及的其他主要接口为 ICorProfilerInfo 和 ICorProfilerInfo2。探查器会根据需要调用这些接口,以获取更多信息来帮助进行分析。例如,每当 CLR 调用 FunctionEnter2 函数时,它都会提供函数标识符。通过调用 ICorProfilerInfo2::GetFunctionInfo2 方法来发现函数的父类、其名称等,探查器可以获得有关该函数的更多信息。