.NET框架程序设计-.NET框架开发平台的体系架构概览(.NET程序本质)

The Architecture of the .NET Framework Development Plateform

[相关术语参考:http://www.microsoft.com/china/msdn/archives/library/faq111700.asp#faq111700_term]


.NET程序的生成以及执行过程:

将源代码编译为托管模块(Managed Module) -> 将托管模块组合成为程序集(Assembly) -> 加载CLR -->执行程序集代码

(1)将源代码编译为托管模块


我们把各种语言利用相应的编译器来编译成为托管模块,编译器相当于一个语法检查器和代码分析器,最后编译成为托管模块(其实在我们日常编译过程中用编译器直接编译成为了程序集Assembly),托管模块是一个需要CLR才能执行的标准Windows可移植可执行(PE,Portable Executable)文件。

PE文件的组成:
PE表头(包含的信息:文件类型(GUI,CUI,DLL);创建时间;)
CLR表头(包含托管模块的一些信息:CLR版本号;入口方法的MethodDef元数据标记;元数据,资源,强命名,标记等)
元数据 (每个托管模块都包含一些元数据表,描述源代码和引用类型中 定义的类型以及成员)
IL代码指令(编译时产生的指令,CLR在运行时将其编译(JIT)为本地CPU指令)    


(2)将托管模块组合成为程序集


CLR并不和托管模块打交道,它和一个或多个托管模块以及一些资源文件的逻辑组合而成的程序集(Assembly)打交道。
Assembly相对于托管模块有多了一个显著的内容:清单--用来描述组成程序集的所有文件,这好比一本书的索引。
我们可以把程序集的资源文件以及各个类型分开,从而实现程序集的分离管理。

(3)加载CLR

Exe文件加载CLR的过程(DLL类似):
托管Exe被调用时,Windows加载这个Exe,发现其.idata部分记录了需要把MSCorEE.dll(微软组件对象运行时执行引擎)加载到进程的地址空间,idata问什么记录这个东西呢?在编译Exe程序的时候,这个PE文件的.text部分嵌入了个x86 stub函数:JMP _CorExeMain,这个函数是从MSCorEE.dll导入的,所以,PE文件的.idata(记录导入程序集的部分)就记录了这个MSCorEE.dll.加载这个DLL后,加载器获得_CorExeMain函数地址,修正托管Exe中的stub函数的JMP指令。stub函数跳转到_CorExeMain函数,_CorExeMain初始化CLR,探测Exe文件的CLR表头,进而确定要执行的托管入口点方法,其IL代码随之编译成为本地CPU指令。CLR跳转并执行本地CPU指令。

(4)执行程序集代码

IL是Microsoft咨询了一些商业上和学术上的编译器的作者之后开发一种独立于CPU的高级机器语言,它能理解对象类型,拥有很多高级的指令,我们可以把它看作一个面向对象的机器语言。

我们可以利用Microsoft提供的IL汇编器ILAsm.exe来写IL程序,反汇编用ILDAsm.exe.

IL不依赖于特定的CPU平台--只要安装相应版本的CLR(当然,Microsoft可以商业上需要,提供更为简洁的CLR,以实现手机,掌上电脑等智能化设备运行.NET程序).

IL虽是机器语言,但CPU还不能直接执行这些指令,JIT(Just-In-Time)即时编译器起到了这个中间作用,把IL编译成为本地CPU指令。

正式因为如此,我们编写的.NET程序在运行的时候,性能方面是不是令人有所担心呢?Microsoft给出了种种安慰的解释,但是,在实际中,我发现至少应用程序的启动速度是令人沮丧的。

Jeffrey Richter在书中说:Microsoft已经在性能发面做了大量的工作,额外的开销已经降到了最低.这句话显然是对.NET应用程序的性能不是令人十分满意的一个肯定。

posted @ 2004-10-19 13:55  cacard  阅读(1267)  评论(1编辑  收藏  举报