ASP.NET框架设计(一)-----Famework是如何执行程序?
沉默很久了,在DotNet Famework也生活了很久, DotNet的世界是精彩的。因此在我的即将毕业之前,打算对我在DotNet中的感悟做一个总结。也做为我原创的一个开始。
很小的时候就常常被告知要建造一座大厦基础非常重要,在接触DotNet几年后渐渐的我才明白了。在DotNet的大厦中1到5层是面向CLR语言的掌握程度(如c#,vb等),5层以上的是从全局来架构一个系统,而大厦地表以下部分是DotNet Framework这个框架运行的核心部分。
Asp.net是一个非常强大的构建web应用或windows GUI程序的平台,他可以非常灵活并相对快速的构建一个目标系统。但大多数人只熟悉Asp.net高层的框架,例如WebForms、WindowForm等。在这个课题上我将总结一些关于我对框架的运行机制的一些理解。
一、公共语言运行库(Common Language Runtime,CLR)
为什么DotNet平台可以使用多种语言来构建目标程序?原因在与公共语言运行库(Common Language Runtime,CLR),CLR可以通过多种语言来使用的运行库(它的另外一个特性是使用异常来报告错误)。实际上,CLR不关心发人员用那种语言来编程。
微软面向CLR创建了几种编辑器(包括:vb的vbc.exe、c#的csc.exe等)和一个中间语言(Intermediate Language,IL)汇编器。运行过程如下:
无论用什么编译器最终生成的都是一个托管模块。托管模块是一个标准的32位PE32文件或一个标准的64位PE32+文件,但他们都需要CLR才能执行
二、元数据(metadata)
元数据(metadata)是一个数据表。该表描述了模块中定义的内容(比如:类型等),还有一部分元数据表描述了托管模块引用的内容。元数据总是嵌入与代码相同的EXE/DLL,编译其同时生成元数据跟代码并绑定到最终生成的托管模块中。
三、中间语言(Intermediate Language,IL)
IL是一种与CPU无关的机器语言,但比大多数机器语言高级得多。高级语言可以通过编译器来生成IL,同样的也可以用汇编语言来写IL。下面我们通过一个方法来理解IL的执行。
为了执行一个方法,该方法对应的IL首先必须转换成本地CPU指令,通过CLR的JIT(just-in-time)编译器来完成。
如图程序,在Main方法执行前,CLR先检测出Main代码引用的所有类型。使得CLR分配一个内部数据结构,用于管理对引用类型的访问。该方法只引用了一个Console类型,CLR为Console类型分配一个单独的内部结构,在这个结构中,Console类型的所有方法都有记录(未文档化函数JITComoiler),每条记录包含一个地址,根据这个地址可以找到方法的实现。
当JITComoiler被调用,JITComoiler会在元数据中搜索被调用方法的IL,验证IL,进而把IL编译成本地cpu指令(本地cpu指令保存在一个动态分配的内存快中)。然后JITComoiler返回CLR之前分配的内部数据结构找到与被调用方法一致的那条记录,然后把把最初掉用它的引用替换成内存块的地址。
当程序第二次调用console
第二次调用console,由于第一次已经对whirtline的代码进行验证和编译,所以可以直接执行内存快的代码。如下图:
因此调用一个方法只有在首次调用时才会造成一定的性能损失,以后调用该方法直接调用本地代码即可。但是JIT编译器将本地cpu指令保存在动态内存中,一旦程序终止,编译好的代码也会被丢弃。所以,如果再次运行程序或同时运行应用程序的两个实例,JIT必须再次的将IL编译成本地指令。
(对于托管代码与非托管代码性能谁更优秀的争论一直在进行。个人保留意见)