关于程序员:程序集加载

5次阅读

共计 2556 个字符,预计需要花费 7 分钟才能阅读完成。

加载过程

JIT 编译器将 IL 代码编译成本地代码时,会查看 IL 代码援用了哪些类型。在运行时,JIT 编译器利用程序集的 TypeRef 和 AssemblyRef 元数据表来确定哪一个程序集定义了所援用的类型。在 AssemblyRef 元数据表的记录项中,蕴含了形成程序集强名称的各个局部。JIT 编译器获取所有这些局部:名称 (无扩展名和门路)、版本、语言文化、公钥标记 (如果被加载的程序集是弱命名的,那么标识中只蕴含:程序集的名称,将不再蕴含版本、语言文化、公钥标记信息),并把它们连接成一个字符串。而后 CLR 尝试将与该标识匹配的一个程序集加载到 AppDomain 中 (如果还没加载的话)。在外部 CLR 通过 System.Reflection.Assembly 类的静态方法 Load 来尝试加载此程序集 (能够显示的将一个程序集加载到 AppDomain 中)。

Assembly 的 Load 办法
  • 加载强命名程序集

Load 办法导致 CLR 向程序集利用一个版本绑定重定向策略,并在 GAC(全局程序集缓存) 中查找对应的程序集。如果没找到,就接着去应用程序的基目录、公有门路子目录和 codebase 地位查找。

  • 加载弱命名程序集

和加载强命名程序集不同的是,Load 不会向应用程序利用版本绑定重定向策略,CLR 也不会去 GAC 中查找程序集。

最初如果 Load 找到指定的程序集,就会返回已加载的程序集的一个 Assembly 对象的援用,如果没有加载到指定程序集,则会抛出一个 System.IO.FileNotFoundException。

AppDomain 的 Load 办法 (尽量不应用)

与 Assembly 的 Load 办法不同,该办法属于实例办法。作用为将一个程序集加载到一个指定的 AppDomain 中。可供非托管代码调用,容许宿主将一个程序集注入一个指定的 AppDomain。托管代码个别不应用该办法,因为在调用该办法后会开始在惯例地位搜查程序集,而 AppDomain 关联了一些设置通知 CLR 如何查找程序集,为了加载程序集 CLR 将应用与指定 AppDomain 关联的设置,而不是收回调用的那个 AppDomain 关联的设置。以及 AppDomain 的 Load 办法返回对程序集的一个援用,因为 System.Assembly 类不是从 System.MarshalByRefObject 派生的,所以程序集必须按值封送回那个发动调用的 AppDomain。当初 CLR 就会用收回调用的 AppDomain 的关联设置来定位并加载程序集。如果收回调用的 AppDomain 没有找到指定的程序集就会抛出 FileNotFountException。这不是咱们冀望的行为,所以尽量避免应用 AppDomain 的 Load 办法。

Assembly 的 LoadFrom 办法

在外部 LoadFrom 会先调用 System.Reflection.AssemblyName 类的静态方法 GetAssemblyName,该办法关上指定的文件,查找 AssemblyRef 元数据表的记录项,提取程序集标识信息,而后返回 System.Reflection.AssemblyName 对象并敞开文件。随后 LoadFrom 办法在外部调用 Assembly 的 Load 办法,将 AssemblyName 对象传给它。接着 CLR 会利用版本绑定重定向策略,并在各个地位查找程序集。如果 Load 找到了匹配的程序集就会加载并返回已加载程序集的一个 Assembly 对象,LoadFrom 办法将返回这个值。如果没有找到匹配的程序集,LoadFrom 就会加载通过 LoadFrom 的实参传递的门路中的程序集。如果已加载了一个具备雷同标识的程序集,LoadFrom 办法会简略返回代表已加载程序集的一个 Assembly 对象。

* 能够给 LoadFrom 办法传递一个 URL 实参,CLR 会被动下载文件并将其装置到用户的下载缓存中,最初再从那加载文件

Assembly 的 LoadFile 办法

调用这个办法能够从任意门路加载一个程序集,并可将具备雷同标识的一个程序集屡次加载到一个 AppDomain 中。通过 LoadFile 加载程序集时,CLR 不会主动解析任何依赖问题,代码必须向 AppDomain 的 AssemblyResolve 事件注销,让事件回调办法显示加载任何依赖的程序集。

Assembly 的 ReflectionOnlyLoadFrom 办法和 ReflectionOnlyLoad 办法
  • ReflectionOnlyLoadFrom: 加载由门路指定的文件,文件的强名称标识不会获取,也不会再 GAC 和其它地位搜寻文件。
  • ReflectionOnlyLoad: 会在 GAC、应用程序基目录、公有门路和 codebase 指定的地位搜寻指定的程序集。和 Load 不同的是不会利用版本控制策略,即指定的什么加载版本,取得的便是哪个版本。
  • ReflectionOnlyLoadFrom 和 ReflectionOnlyLoad: 这两个办法加载程序集时,CLR 都会禁止程序集中的任何代码执行。试图执行这两个办法加载的程序集中的代码,都会导致 CLR 抛出 InvalidOperationException。
存在多个具备雷同标识的程序集

一台机器上可能共事存在多个具备雷同标识的程序集,因为 LoadFrom 会在外部调用 Load 办法,所以 CLR 有可能不加载你指定的文件,而是加载一个不同的文件,从而达不到预期成果。倡议每次生成程序集都批改版本号,确保每个版本都有本人的惟一标识,进而确保 LoadFrom 办法能达到预期行为。

程序集卸载

CLR 并未提供独自卸载某个程序集的性能,因为一旦这种行为被容许,那么一旦线程从某个办法返回至已卸载的程序集中的代码,应用程序就会解体。要卸载程序集必须卸载程序集所在的整个 AppDomain。而应用 ReflectionOnlyLoadFrom 办法和 ReflectionOnlyLoad 办法加载的程序集因为程序集中的代码不容许被执行,让人看上去这些程序集是能够卸载的,实际上 CLR 也不容许卸载这两个办法加载的程序集,因为即使不会运行程序集中的代码但依然能够利用反射来创建对象,援用程序集中定义的元数据,如果程序集被卸载就必须使这些对象有效,从实现复杂度还是执行速度上来讲跟踪这些对象的状态都是得失相当的。

正文完
 0