This documentation is archived and is not being maintained.

Object Inspection in the Profiling API

This topic discusses how to use profiling methods to inspect objects.

The FunctionEnter2 and FunctionLeave2 callbacks provide information about the arguments and return value of a function, as regions of memory. The arguments are stored from left to right in the given memory regions. A profiler can use the metadata signature of the function to interpret the arguments, as shown in the following table.

ELEMENT_TYPE

Representation

Primitives (ELEMENT_TYPE <= R8, I, U)

Primitive values.

Value types (VALUETYPE)

Depends on type.

Reference types (CLASS, STRING, OBJECT, ARRAY, GENERICINST, SZARRAY)

ObjectID (pointer into a garbage collection heap).

BYREF

Managed pointer (not an ObjectID, but may be pointing to a stack or garbage collection heap).

PTR

Unmanaged pointer (not movable by garbage collection).

FNPTR

Pointer-sized opaque value.

TYPEDBYREF

Managed pointer, followed by a pointer-sized opaque value.

The differences between an ObjectID and a managed pointer are as follows:

  • ObjectIDs point only into the garbage collection heap or frozen object heap. Managed pointers may also point to the stack.

  • ObjectIDs always point to the beginning of an object. Managed pointers may point to one of the object's fields.

  • Managed pointers cannot be passed to functions that expect an ObjectID.

See the CorElementType enumeration for a list of the available CLR types.

Inspecting reference types or non-primitive value types involves some advanced techniques.

For value types and reference types other than strings or arrays, the ICorProfilerInfo2::GetClassLayout method provides the offset for each field. The profiler can then use the metadata to determine the type of the field and recursively evaluate it.

NoteNote

GetClassLayout returns only the fields that are defined by the class itself; fields that are defined by the parent class are not included. You can use the ICorProfilerInfo2::GetClassIDInfo2 method to find the ClassID of the parent class, and then use GetClassLayout to obtain information about the fields defined by the parent class.

For boxed value types, the ICorProfilerInfo2::GetBoxClassLayout method provides the offset of the value type within the box. The layout of the value type itself does not change. Therefore, as soon as the profiler has found the value type within the box, it can use GetClassLayout to understand its layout.

For strings, the ICorProfilerInfo2::GetStringLayout method provides the offsets of interesting pieces of data in the string object.

Arrays are somewhat special in that you must call a method for each array object instead of each array type. (This is because there are too many array formats to describe by using offsets.) The ICorProfilerInfo2::GetArrayObjectInfo method is provided to do the interpretation.

There are four types of static fields. The following table describes what they are and how to identify them.

Static type

Definition

How it appears in metadata

AppDomain

Your basic static field. It has a different value in each application domain.

Static field that has no attached custom attributes.

Thread

Managed thread-local storage (TLS). This is a static field with a unique value for each thread and each application domain.

Static field marked with ThreadStaticAttribute.

RVA

Process-scoped static field with a home in the module's data section.

Static field with hasRVA flag.

Context

Static field with a different value in each COM+ context.

Static field marked with ContextStaticAttribute.

The ICorProfilerInfo2::GetThreadStaticAddress, ICorProfilerInfo2::GetAppDomainStaticAddress, ICorProfilerInfo2::GetContextStaticAddress, and ICorProfilerInfo2::GetRVAStaticAddress methods provide information about the location of static fields. Looking at the memory at that location, you interpret it as follows:

  • Reference types: ObjectID.

  • Value types: ObjectID of box that contains the actual value.

  • Primitive types: Primitive value.

Show: