可回收程序集是一个动态程序集,卸载该程序集时,无需卸载在其中创建了该程序集的应用程序域。 可回收程序集使用的所有托管和非托管内存及其包含的类型都是可回收的。 从内部数据表中删除程序集名称等信息。
若要启用卸载,请在创建动态程序集时使用 AssemblyBuilderAccess.RunAndCollect 标志。 程序集是暂时性的(即,无法保存),并且受 可收集程序集 部分的限制中所述的限制。 公共语言运行时(CLR)在释放与程序集关联的所有对象时自动卸载可收集的程序集。 在所有其他方面,可收集程序集的创建和使用方式与其他动态程序集相同。
可回收程序集的生存期
可回收程序集的生存期受控于是否存在对其包含的类型和从这些类型创建的对象的引用。 公共语言运行时不会卸载程序集,前提是存在以下一个或多个程序集(T
是程序集中定义的任何类型的):
T
的实例。一个数组
T
的实例。泛型类型的一个实例,其中包含
T
作为其类型参数之一。 这包括泛型集合T
,即使该集合为空也是如此。Type 或 TypeBuilder 的一个实例,表示
T
。重要
必须释放表示部分程序集的所有对象。 定义ModuleBuilder的
T
保留对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>
在 C#中)或 List(Of Integer)
(在 Visual Basic 中)被视为已在包含泛型类型定义的程序集或包含其类型参数定义的程序集中定义。 使用的具体程序集是实现的细节,可能会发生更改。
对可回收程序集的限制
以下限制适用于可收集的组件:
静态引用
普通动态程序集中的类型不能具有对可回收程序集中定义的类型的静态引用。 例如,如果定义了普通类型,且该类型继承自可回收程序集中的类型,则会引发 NotSupportedException 异常。 可收集程序集中的类型可以具有对另一个可收集程序集中的类型的静态引用,但这会将引用的程序集的生存期延长到引用程序集的生存期。
以下限制适用于 .NET Framework 中的可收集程序集:
COM 互操作
无法在可收集程序集中定义 COM 接口,并且可收集程序集中的类型实例无法转换为 COM 对象。 可回收程序集中的类型不可用作 COM 可调用包装器 (CCW) 或运行时可调用包装器 (RCW)。 但是,可回收程序集中的类型可以使用实现 COM 接口的对象。
平台调用
在可回收程序集中声明具有 DllImportAttribute 特性的方法时,该方法不会进行编译。 OpCodes.Calli 指令不能用于可回收程序集中类型的实现,并且不可将此类类型封送到非托管代码。 但是,仍可使用非可回收程序集中声明的入口点调入本机代码。
封送
无法封送可回收程序集中定义的对象(尤其是委托)。 这是对所有暂时性发出的类型的限制。
程序集加载
对于加载可回收程序集,反射发出是支持的唯一机制。 使用任何其他形式的程序集加载机制加载的程序集无法卸载。
上下文绑定对象
不支持上下文静态变量。 可回收程序集中的类型无法扩展 ContextBoundObject。 但是,可回收程序集中的代码可使用在其他位置定义的上下文绑定对象。
线程静态数据
不支持线程静态变量。
以下限制适用于 .NET Framework 和 .NET 9 之前的 .NET 版本中的可收集程序集:
具有
FixedAddressValueTypeAttribute
的静态字段在可回收程序集中定义的静态字段不能应用 FixedAddressValueTypeAttribute 特性。