动态类型生成的可回收程序集
可回收程序集属于动态程序集,可以在不必卸载用于创建这些程序集的应用程序域的情况下,卸载这些程序集。 可回收程序集使用的所有托管和非托管内存及其包含的类型均会进行回收, 并将从内部表中删除程序集名称之类的信息。
若要启用卸载功能,请在创建动态程序集时使用 AssemblyBuilderAccess.RunAndCollect 标记。 可回收程序集是瞬态的(即,无法保存),并会受到针对可回收程序集的限制一节中所述的限制的约束。 当您释放了与可回收程序集关联的所有对象之后,公共语言运行时 (CLR) 会自动卸载该程序集。 在所有其他方面,可回收程序集的创建和使用方式都与其他动态程序集相同。
可回收程序集的生存期
可回收动态程序集的生存期受是否存在对其所包含类型(及从这些类型创建的对象)的引用的控制。 只要存在以下的一个或多个项,公共语言运行时就不会卸载程序集(T 表示在程序集中定义的任何类型):
T 的一个实例。
T 数组的一个实例或使用 T 作为一个类型参数的泛型集合的一个实例(即使这类数组或集合为空)。
表示 T 的 Type 或 TypeBuilder 的一个实例。
注意 |
---|
您必须释放表示程序集的各部分的所有对象。由于已定义 T 的 ModuleBuilder 会保留对 TypeBuilder 的引用,并且 AssemblyBuilder 对象会保留对 ModuleBuilder 的引用,因此必须释放对这些对象的引用。甚至,如果存在 T 构造中使用的 LocalBuilder 或 ILGenerator,也会阻止卸载。 |
另一个仍可通过执行代码来访问的动态定义类型 T1 对 T 的静态引用。 例如,T1 可能派生自 T,或者 T 可能是 T1 的方法中的参数的类型。
对属于 T 的静态字段的 ByRef 引用。
引用 T 或 T 的某个组件的 RuntimeTypeHandle、RuntimeFieldHandle 或 RuntimeMethodHandle。
任何具有以下特点的反射对象的一个实例:可以间接或直接地使用此类反射对象来访问表示 T 的 Type 对象。 例如,可以从其元素类型为 T 的数组类型中或者从使用 T 作为类型参数的泛型类型中,获取 T 的 Type 对象。
任何线程的调用堆栈上的 M 方法,其中 M 是 T 的方法或程序集中定义的模块级方法。
针对在程序集模块中定义的静态方法的委托。
如果程序集中的一个类型或一个方法在此列表中只有一个对应项,则运行时将无法卸载程序集。
注意 |
---|
只有在针对此列表中的所有项运行终结器之后,运行时才会实际卸载程序集。 |
出于跟踪生存期的目的,对于在可回收程序集生成中创建和使用的构造泛型类型,如 List<int>(在 Visual Basic 中为 List(Of Integer)),假定已经在包含泛型类型定义的程序集中或在包含其类型参数的定义的程序集中进行了定义。 所使用的确切程序集属于实现细节,可能会发生更改。
针对可回收程序集的限制
下列限制适用于可回收程序集:
静态引用 普通动态程序集中的类型不能具有对在可回收程序集中定义的类型的静态引用。 例如,如果定义一个继承可回收程序集中的类型的普通类型,则将引发 NotSupportedException 异常。 一个可回收程序集中的类型可以具有对另一个可回收程序集中的类型的静态引用,但这会将所引用的程序集的生存期扩展为引用程序集的生存期。
COM 互操作 不能在可回收程序集中定义任何 COM 接口,并且不能将可回收程序集中的任何类型实例转换为 COM 对象。 不能将可回收程序集中的类型用作 COM 可调用包装 (CCW) 或运行时可调用包装 (RCW)。 但是,可回收程序集中的类型可以使用实现 COM 接口的对象。
平台调用 在可回收程序集中声明具有 DllImportAttribute 特性的方法时,这些方法将不会编译。 不能在可回收程序集中的类型实现中使用 OpCodes.Calli 指令,并且不能将此类类型封送到非托管代码。 但是,您可以通过使用在非可回收程序集中声明的入口点来调入本机代码。
封送 不能封送在可回收程序集中定义的对象(具体是指委托)。 这是对所有瞬态发出的类型的限制。
程序集加载 反射发出是唯一支持的用于加载可回收程序集的机制。 不能卸载由任何其他形式的程序集加载的程序集。
上下文绑定对象 不支持上下文静态变量。 可回收程序集中的类型不能扩展 ContextBoundObject。 但是,可回收程序集中的代码可以使用在其他位置定义的上下文绑定对象。
线程静态数据 不支持线程静态变量。