Επεξεργασία

Κοινή χρήση μέσω


Collectible assemblies for dynamic type generation

Collectible assemblies are dynamic assemblies that can be unloaded without unloading the application domain in which they were created. All managed and unmanaged memory used by a collectible assembly and the types it contains can be reclaimed. Information such as the assembly name is removed from internal tables.

To enable unloading, use the AssemblyBuilderAccess.RunAndCollect flag when you create a dynamic assembly. The assembly is transient (that is, it cannot be saved) and is subject to limitations described in the Restrictions on collectible assemblies section. The common language runtime (CLR) unloads a collectible assembly automatically when you release all objects associated with the assembly. In all other respects, collectible assemblies are created and used in the same way as other dynamic assemblies.

Lifetime of collectible assemblies

The lifetime of a collectible assembly is controlled by the existence of references to the types it contains and the objects that are created from those types. The common language runtime does not unload an assembly as long as one or more of the following exist (T is any type that is defined in the assembly):

  • An instance of T.

  • An instance of an array of T.

  • An instance of a generic type that has T as one of its type arguments. This includes generic collections of T, even if that collection is empty.

  • An instance of Type or TypeBuilder that represents T.

    Important

    You must release all objects that represent parts of the assembly. The ModuleBuilder that defines T keeps a reference to the TypeBuilder, and the AssemblyBuilder object keeps a reference to the ModuleBuilder, so references to these objects must be released. Even the existence of a LocalBuilder or an ILGenerator used in the construction of T prevents unloading.

  • A static reference to T by another dynamically defined type T1 that is still reachable by executing code. For example, T1 might derive from T, or T might be the type of a parameter in a method of T1.

  • A ByRef to a static field that belongs to T.

  • A RuntimeTypeHandle, RuntimeFieldHandle, or RuntimeMethodHandle that refers to T or to a component of T.

  • An instance of any reflection object that could be used indirectly or directly to access the Type object that represents T. For example, the Type object for T can be obtained from an array type whose element type is T, or from a generic type that has T as a type argument.

  • A method M on the call stack of any thread, where M is a method of T or a module-level method that is defined in the assembly.

  • A delegate to a static method that's defined in a module of the assembly.

If only one item from this list exists for only one type or one method in the assembly, the runtime cannot unload the assembly.

Note

The runtime does not actually unload the assembly until finalizers have run for all items in the list.

For purposes of tracking lifetime, a constructed generic type such as List<int> (in C#) or List(Of Integer) (in Visual Basic) that's created and used in the generation of a collectible assembly is considered to have been defined either in the assembly that contains the generic type definition or in an assembly that contains the definition of one of its type arguments. The exact assembly that's used is an implementation detail and subject to change.

Restrictions on collectible assemblies

The following restrictions apply to collectible assemblies:

  • Static references

    Types in an ordinary dynamic assembly cannot have static references to types that are defined in a collectible assembly. For example, if you define an ordinary type that inherits from a type in a collectible assembly, a NotSupportedException exception is thrown. A type in a collectible assembly can have static references to a type in another collectible assembly, but this extends the lifetime of the referenced assembly to the lifetime of the referencing assembly.

The following restrictions apply to collectible assemblies in .NET Framework:

  • COM interop

    No COM interfaces can be defined within a collectible assembly, and no instances of types within a collectible assembly can be converted into COM objects. A type in a collectible assembly cannot serve as a COM callable wrapper (CCW) or runtime callable wrapper (RCW). However, types in collectible assemblies can use objects that implement COM interfaces.

  • Platform invoke

    Methods that have the DllImportAttribute attribute will not compile when they're declared in a collectible assembly. The OpCodes.Calli instruction cannot be used in the implementation of a type in a collectible assembly, and such types cannot be marshalled to unmanaged code. However, you can call into native code by using an entry point that's declared in a non-collectible assembly.

  • Marshaling

    Objects (in particular, delegates) that are defined in collectible assemblies cannot be marshalled. This is a restriction on all transient emitted types.

  • Assembly loading

    Reflection emit is the only mechanism that's supported for loading collectible assemblies. Assemblies that are loaded by using any other form of assembly loading cannot be unloaded.

  • Context-bound objects

    Context-static variables are not supported. Types in a collectible assembly cannot extend ContextBoundObject. However, code in collectible assemblies can use context-bound objects that are defined elsewhere.

  • Thread-static data

    Thread-static variables aren't supported.

The following restrictions apply to collectible assemblies in .NET Framework and .NET versions prior to .NET 9:

  • Static fields with FixedAddressValueTypeAttribute

    Static fields that are defined in collectible assemblies cannot have the FixedAddressValueTypeAttribute attribute applied.

See also