分析和运行时通知 ID

运行时通知为报告的类、线程、应用程序域等提供 ID。 可以使用这些 ID 来查询公共语言运行时 (CLR) 以获得更多信息。 每个 ID 都是描述该项的一个内存块的地址。 但是,探查器应将 ID 视为不透明句柄。 如果在分析函数调用中使用无效的 ID,结果将不明确。 最有可能出现的结果是访问冲突。 探查器必须确保所使用的 ID 是有效的。 分析 API 不执行任何类型的验证,因为这将会产生系统开销,并大大拖慢应用程序的执行速度。

以下各节描述分析 API 中 ID 的特性。

唯一性

在进程的生存期内,ProcessID 在系统范围内是唯一的。 在 ID 的生存期内,所有其他 ID 都是进程范围的唯一 ID。

层次结构和包容

ID 排列在与进程中的层次结构相对应的层次结构中。 进程包含应用程序域,应用程序域包含程序集,程序集包含模块,模块包含类,而类又包含函数。 线程包含在进程内,并且可在应用程序域之间移动。 对象通常包含在应用程序域内,并且只有极少数对象可能同时是多个应用程序域的成员。 上下文包含在进程内。

生存期和稳定性

当给定进程、应用程序域、程序集、线程或对象被销毁、释放或解锁时,或者在其结束时,与之关联的 ID 将变为无效。 当给定 ID 变为无效时,它包含的所有 ID 也将变为无效。 例如,某个应用程序域卸载后,它的 AppDomainID 将变为无效。 与应用程序域内的程序集、模块、类和函数对应的 AssemblyID、ModuleID、ClassID 和 FunctionID 也将同时变为无效。

特定 ID 的生存期和稳定性如下所示:

应用程序域关联

进程中每个用户创建的应用程序域都有 AppDomainID。 默认域和一个特殊的伪域(用于容纳非特定于域的程序集)也有 AppDomainID。

程序集、模块、类、函数和垃圾回收器句柄具有应用程序域关联。 这意味着,如果将一个程序集加载到多个应用程序域中,则该程序集及其所有模块、类、函数和垃圾回收器句柄在每个应用程序域中将有不同的 ID,并且,针对各个 ID 的操作只会在关联的应用程序域中生效。 非特定于域的程序集出现在前面提到的特殊的伪域中。

其他说明

除 ObjectID 之外的所有 ID 应被视作不透明值。 大多数 ID 的含义都一目了然。 但有必要对以下 ID 加以更详细的说明:

  • ClassID 表示类。 如果是泛型类,则它们表示完全实例化的类型。 List<int>、List<char>、List<object> 和 List<string> 都有其自己的 ClassID。 List<T> 是未实例化的类型,并且没有 ClassID。 Dictionary<string,V> 是部分实例化的类型,并且没有 ClassID。

  • FunctionID 表示函数的本机代码。 如果是泛型函数(或泛型类上的函数),则给定函数可能存在多个本机代码实例化,并因此可能存在多个 FunctionID。 可以在不同的类型(例如,List<string> 和 List<object> 共享代码)之间共享本机代码实例化,因此,一个 FunctionID 可能属于多个 ClassID。

  • ObjectID 表示被作为垃圾回收的对象。 ObjectID 是探查器收到 ObjectID 时对象的当前地址,并且可能随着每次垃圾回收发生变化。 因此,只有在收到 ObjectID 值直至下一次垃圾回收开始时的这段时间内,ObjectID 值才是有效的。 CLR 还为探查器提供了通知,用于更新其内部对象跟踪映射,以使探查器在多次垃圾回收过程中能够保持一个有效的 ObjectID。

  • GCHandleID 表示垃圾回收的句柄表中的项。 GCHandleID(与 ObjectID 不同)是不透明值。 垃圾回收句柄在某些情况下由 CLR 本身创建,或者,也可以使用 GCHandle 结构创建垃圾回收句柄。 (请注意,GCHandle 结构只是表示句柄;句柄未包含在结构中。)

  • ThreadID 表示托管线程。 如果宿主支持在纤程模式下执行,则托管线程可能存在于不同的操作系统线程上,具体情况视何时检查托管线程而定。

    注意注意

    .NET Framework 2.0 版中不支持对纤程模式应用程序进行分析。

请参见

概念

分析概述