在CLR中,程序集相当于“组件”。
程序集的产生过程:
C#
源代码文件----->(经过编译器[CSC.exe]编译) ------->生成托管模块 (如果当前项目只有一个托管模块且没有资源文件,则此时的托管模块就是程序集)
如果有多个托管模块和资源文件 -------------------->(经过编译器csc.exe编译)------------->生成程序集(此时会产生一个清单: 描述程序集中的文件集)
程序集的优点:
1,利用程序集,可以在不同的地方部署文件,同时仍然将所有文件作为一个整体来对待。例如,可以将很少用到的类型或资源放到单独的文件中,并把这些文件作为程序集的一部分,这些可以取决于运行时的需要,可从网上下载这些单独的文件,如果用不上,则永远不会下载,这样不仅节省磁盘空间,还缩短了安装时间;
2,程序集与非托管组件相比,它不需要在注册表或 Active Directory Domain Services(ADDS)中保存额外的信息,所以它部署起来更容易
执行程序集的代码
執行程序集代碼(1).jpg執行程序集代碼(2).jpg
如前两张图所示,首先,在Main方法执行之前,CLR 会检测出Main的代码引用的所有类型。这导致CLR分配一个内部数据结构来管理对引用类型的访问。Main方法在首次调用WriteLine方法时,CLR 的JITCompiler函数也会被调用,它负责将方法的IL代码编译成本机CPU指令,由于IL是“即时”编译的,所以将MSCorEE组件称为即时编译器。此时,方法第一次调用,在性能上会有些损失,JITCompiler函数被调用时,它知道要调用的是哪个方法,以及具体是什么类型定义了该方法,然后JITCompiler会在定义(该类型的)程序集的元数据中查找被调用方法的IL。接着JITCompiler验证IL代码,并将IL代码编译成本机CUP指令。本机CPU指令保存到动态分配的内存块中。然后,JITCompiler回到CLR为类型创建的内部数据结构,找到与被调用方法对应的那条记录,修改最初对JITCompiler的引用,使其指向内存块(其中包含了刚才变异好的本机CPU指令)的地址。最后,JITCompiler函数跳转到内存块中的代码。这些代码正是WriteLine方法(获取单个String参数的那个版本)的具体实现。代码执行完毕返回时,会回到Main 中的代码,并像往常一样继续执行。
接着在第二次调用WriteLine方法时,由于第一次已经生成了本机代码,且被调用的方法也指向内存块的地址,内存中已有记录,所以,第二次JITComipler方法不会再执行,而是直接在执行内存块中的代码。所以后面所有对该方法的调用都会以本机代码的形式全速运行,无需重新验证IL并把它编译成本机代码。
IL基于栈,IL最大的优势不是它对底层CPU的的抽象,而是应用程序的健壮性和安全性。
将IL变异成本机CPU指令时,CLR会执行一个名为验证的过程。这个过程会检查高级IL代码,确定代码所做的一切都是安全的。
使用托管代码的优点:
1,托管代码会将所有Windows进程放入独立的地址空间,将获得健壮性和稳定性,一个进程干扰不到另一个进程;
2,但如果进程数量太多,会损害性能并制约可用的资源,而托管代码可以用一个进程运行多个应用程序,以此减少进程数,从而增强性能,减少所需的资源
CLR的宿主进程(如IIS,Microsoft SQL Server)可决定在一个进程中运行多个AppDomain,每个应用程序都是在一个AppDomain中运行,而一个地址空间只有一个AppDomain
网友评论