进程内并行分析
从 .NET Framework 4 开始,可以在同一进程中并行运行多个 .NET Framework 版本。 探查器必须能够识别并行方式才能在此环境中运行。如果要分析的进程未承载多个 .NET Framework 版本,则可以在 .NET Framework 4 版中使用设计为与 .NET Framework 2.0 版、.NET Framework 2.0 SP1、.NET Framework 3.0、.NET Framework 3.5 或 .NET Framework 3.5 SP1 一起使用的探查器。 有关如何使用进程内并行分析的更多信息,请参见探查器兼容性设置。
并行感知
如果探查器可确保加载多个运行时的应用程序不会导致自身发生意外损坏(如访问冲突),则探查器是并行感知的。 并行感知包含以下级别的支持:
分析第一个。 分析加载到进程中的第一个公共语言运行时 (CLR) 版本,但不分析后续的 CLR 版本。 探查器必须准备好对其 COM 类工厂对象调用 CreateInstance 多次,但无需支持对其 COM 对象的多个实例同时进行回调。 探查器只接受第一个类工厂 CreateInstance 调用和 Initialize 回调调用,而不接受剩余调用。
分析一个。 此级别的支持与“分析第一个”类似,只不过探查器允许用户选择要分析的 CLR 版本,而不是仅分析加载的第一个 CLR 版本。
分析多个。 用户选择一个或多个(可能是所有)要分析的 CLR 版本。 探查器使用来自这些 CLR 版本的回调并将 Info 函数调回适当的版本。 这需要探查器跟踪运行时项(函数、应用程序域、类、对象等)属于哪个 CLR。
注意 |
---|
为 .NET Framework 4 设计的探查器必须是并行感知的。也就是说,如果探查器实现 ICorProfilerCallback3 接口,则它必须实现上述方案之一(“分析第一个”、“分析一个”或“分析多个”)以确保多个运行时不会导致探查器发生意外损外。 |
“分析多个”支持的要求
若要支持“分析多个”选项,探查器必须能执行下列操作:
将对全局函数的调用与适当的运行时关联。
将各种 ID(如 ObjectID、FunctionID、ClassID、ModuleID、AssemblyID、AppDomainID 等)与适当的运行时关联,并确保来自一个运行时的 ID 绝不会传递给另一个运行时的 ICorProfilerCallback(2,3) 接口。 但是,将来自任何运行时或本机代码的任意指令指针传递到任何运行时的 ICorProfilerInfo::GetFunctionFromIP 方法的实现中是可以接受的。
处理运行时之间的交互,例如从一个运行时传递到另一个运行时的调用堆栈。
处理它的用于实现在同一进程中处于活动状态的 ICorProfilerCallback(2,3) 的类的多个实例。
探查器通常应提供一个探查器管理器对象,此对象负责处理全局函数实现和跨越多个运行时的数据。 例如:
来自所有运行时的 Enter/leave/tailcall/FunctionIDMapperFunctionIDMapper 函数 回调。 此探查器管理器对象通常将使用来自 FunctionIDMapper2 或 ICorProfilerInfo3::SetFunctionIDMapper2 的 clientData 参数来确定相应的运行时。
运行时之间的堆栈审核和隐藏堆栈。
运行时之间的协调日志记录。
探查器还必须提供实现 ICorProfilerCallback 接口的探查器对象。 CLR 会为每个活动运行时实例化此探查器对象一次。 探查器管理器是探查器应访问的唯一全局对象。 探查器不应保持对其 ICorProfilerCallback 实现的全局引用,因为在进程包含多个运行时的情况下,ICorProfilerCallback 实现的多个实例可以处于活动状态。
激活探查器
主要的激活任务是将探查器与运行时版本相关联。
启动探查器
若要在给定进程内的所有运行时中启动一个探查器,请设置 COR_PROFILER 和 COR_ENABLE_PROFILING 环境变量。 (此过程与 .NET Framework 3.5 和早期版本中的过程相同。)
如果只希望在某些运行时中启动探查器,请设置 COR_PROFILER 和 COR_ENABLE_PROFILING 环境变量并执行下列操作之一:
使除对类工厂对象的第一个 CreateInstance 调用之外的所有调用失败(“分析第一个”)。
- 或 -
允许对类工厂对象的所有 CreateInstance 调用,并在 Initialize 调用中确定正在调用的运行时的版本。 为此,您必须同时执行下面的两个操作:
对 ICorProfilerInfo3 接口的 CLR 执行 QueryInterface 方法。 如果此操作失败,则表示运行时的版本为 1 或 2.0。 对 ICorProfilerInfo2 接口执行 QueryInterface 可获知运行时的版本是 2.0 还是 1。
如果 ICorProfilerInfo3 受支持,请调用 GetRuntimeInformation 方法以获取有关要分析的运行时的更多信息。
在确定运行时的版本后,探查器可以决定是否分析该运行时。 如果探查器决定分析该运行时,则按常规方式继续进行初始化。 如果探查器决定不分析该运行时,则从 Initialize 返回错误。 从 .NET Framework 4 开始,探查器可以返回 CORPROF_E_PROFILER_CANCEL_ACTIVATION HRESULT 以避免将错误记录到 Windows 应用程序事件日志中。
附加探查器
附加触发器进程将执行下列操作:
使用 ICLRMetaHost::EnumerateLoadedRuntimes 方法枚举加载到目标进程中的运行时并查找相关运行时。
从 ICLRMetaHost::EnumerateLoadedRuntimes 方法所返回的 IEnumUnknown 接口检索 ICLRRuntimeInfo 接口。
通过使用 CLSID_CLRProfiling 和 IID_ICLRProfiling 对 ICLRRuntimeInfo 接口调用 GetInterface 来获取 ICLRProfiling 接口。
通过 ICLRProfiling 接口调用 AttachProfiler 方法。
有关附加探查器的更多信息,请参见探查器附加和分离。