Identificadores para notificaciones en tiempo de ejecución y generación de perfiles
Las notificaciones en tiempo de ejecución proporcionan un Id. para las clases, subprocesos, dominios de aplicación, etc. de los que se informa. Estos Id. se pueden utilizar para consultar más información en Common Language Runtime (CLR). Cada Id. es la dirección de un bloque de memoria que describe el elemento. Sin embargo, los generadores de perfiles deben tratar los Id. como identificadores opacos. Si se utiliza un Id. no válido en una llamada a una función de generación de perfiles, los resultados son indefinidos. Lo más probable es que el resultado sea una infracción de acceso. El generador de perfiles tiene que asegurarse de que los identificadores que se utilizan sean válidos. La API de generación de perfiles no realiza ningún tipo de validación, porque eso crearía sobrecarga y ralentizaría considerablemente la ejecución de la aplicación.
Las secciones siguientes describen las características de los Id. en la API de generación de perfiles.
Exclusividad
Un ProcessID es único para todo el sistema durante la duración del proceso. Todos los otros Id. son únicos para todo el proceso mientras dure el Id.
Jerarquía y contención
Los Id. están organizados en una jerarquía que refleja la jerarquía del proceso. Los procesos contienen dominios de aplicación, que contienen ensamblados, que contienen módulos, que contienen clases, que contienen funciones. Los subprocesos se contienen dentro de procesos y pueden moverse de dominio de aplicación a dominio de aplicación. Los objetos se contienen principalmente en dominios de aplicación y muy pocos objetos pueden ser miembros de varios dominios de aplicación al mismo tiempo. Los contextos se contienen dentro de procesos.
Duración y estabilidad
Cuando un proceso, dominio de aplicación, ensamblado, subproceso u objeto determinado se destruye, libera o finaliza, el Id. que tiene asociado deja de ser válido. Cuando un Id. determinado deja de ser válido, todos los Id. que contiene dejan también de ser válidos. Por ejemplo, cuando se descarga un dominio de aplicación, su AppDomainID deja de ser válido. Los AssemblyID, ModuleID, ClassID y FunctionID correspondientes a los ensamblados, módulos, clases y funciones dentro del dominio de aplicación se también dejan de ser válidos al mismo tiempo.
La duración y estabilidad de Id. concretos son como sigue:
ProcessID: activo y estable desde la llamada al método ICorProfilerCallback::Initialize hasta el retorno del método ICorProfilerCallback::Shutdown.
AppDomainID: activo y estable desde la llamada al método ICorProfilerCallback::AppDomainCreationFinished hasta el retorno del método ICorProfilerCallback::AppDomainShutdownStarted.
AssemblyID, ModuleID, ClassID: activo y estable desde la llamada al método LoadFinished para el Id. hasta el retorno del método UnloadStarted para el Id.
FunctionID: activo y estable desde la llamada al método ICorProfilerCallback::JITCompilationFinished o ICorProfilerCallback::JITCachedFunctionSearchFinished hasta la destrucción del ClassID contenedor.
ThreadID: activo y estable desde la llamada al método ICorProfilerCallback::ThreadCreated hasta el retorno del método ICorProfilerCallback::ThreadDestroyed.
ObjectID: inicio activo con la llamada al método ICorProfilerCallback::ObjectAllocated. Puede cambiar o inactivarse con cada recolección de elementos no utilizados.
GCHandleID: activo desde la llamada al método ICorProfilerCallback2::HandleCreated hasta el retorno del método ICorProfilerCallback2::HandleDestroyed.
Además, cualquier Id. que se devuelva desde una función de generación de perfiles estará activo en el momento en que se devuelva.
Afinidad de dominio de Aplicación
Cada dominio de aplicación creado por usuario en un proceso tiene un AppDomainID. El dominio predeterminado y un pseudodominio especial que se utiliza para contener ensamblados neutrales respecto a dominio también tienen AppDomainID.
Los ensamblados, módulos, clases, funciones e identificadores del recolector de elementos no utilizados tienen afinidad de dominio de aplicación. Esto significa que si se carga un ensamblado en varios dominios de aplicación, el ensamblado y todos sus módulos, clases, funciones e identificadores de recolector de elementos no utilizados tendrán un Id. diferente en cada dominio de aplicación, y que las operaciones en cada Id. sólo tendrán efecto en el dominio de aplicación asociado. Los ensamblados neutrales respecto a dominio aparecen en el pseudodominio especial mencionado anteriormente.
Notas adicionales
Todos los Id. excepto ObjectID se deben tratar como valores opacos. La mayoría de los Id. son bastante autoexplicativos. Los Id. siguientes merecen una explicación más detallada:
Los ClassID representan clases. En el caso de las clases genéricas, representan tipos totalmente con instancias. Cada objeto List<int>, List<char>, List<object> y List<string> tiene su propio ClassID. List<T> es un tipo sin instancia y no tiene ningún ClassID. Dictionary<string,V> es un tipo parcialmente con instancias y no tiene ningún ClassID.
Los FunctionID representan el código nativo para una función. En el caso de funciones genéricas (o funciones en clases genéricas), es posible que existan varias instancias de código nativo y, por consiguiente, varios FunctionID, para una función determinada. Las instancias de código nativo se pueden compartir entre diferentes tipos (por ejemplo, List<string> y List<object> comparten el código), por lo que un FunctionID puede pertenecer a más de un ClassID.
Los ObjectID representan objetos recolectados como elementos no utilizados. Un ObjectID es la dirección actual de un objeto en el momento en el que el generador de perfiles recibe el ObjectID, y puede cambiar con cada recolección de elementos no utilizados. Por consiguiente, un valor ObjectID solamente es válido entre el momento en el que se recibe y el momento en el que se inicia la siguiente recolección de elementos no utilizados. CLR también proporciona notificaciones para que un generador de perfiles actualice sus asignaciones de seguimiento de objetos, para que el generador de perfiles pueda mantener un ObjectID entre recolecciones de elementos no utilizados.
Los GCHandleID representan entradas de la tabla de identificadores de la recolección de elementos no utilizados. Los GCHandleID, a diferencia de los ObjectID, son valores opacos. El propio CLR crea identificadores de recolección de elementos no utilizados en algunos casos; también se pueden crear utilizando la estructura GCHandle. (Observe que la estructura GCHandle solamente representa el identificador; el identificador no está contenido en la estructura.)
ThreadID representa subprocesos administrados. Si un host admite la ejecución en modo de fibra, un subproceso administrado puede existir en diferentes subprocesos del sistema operativo, en función de cuándo se examine.
Nota La generación de perfiles de aplicaciones de modo de fibra no es compatible con la versión 2.0 de .NET Framework.