您的位置:首页 > 其它

Chapter1 CLR的执行模式

2013-01-07 14:12 267 查看

1.1将源代码编译成托管模块

一、托管模块的各个组成部分

1.PE32或PE32+头,标准的WindowsPE文件头,如果这个头使用的是PE32格式,文件只能在32或64位系统上运行,如果头是PE32+格式只能在64位系统上运行

2.CLR头

3.元数据,一组数据表,主要包含两种表:①描述源代码中定义的类型和成员②描述源代码引用的类型和成员。

4.IL(中间语言)代码,编译器编译源代码时生成的代码,在运行时,CLR将IL编译成本地CPU指令。

二、元数据多种用途

1.编译时,元数据消除了对本地C/C++头和库文件的需求(在IL代码文件中,已经包含和引用的类型/成员有关的全部信息,编译器可以直接从托管模块读取元数据)。

2.使用元数据帮你写代码————智能感知。

3.CLR的代码验证过程使用元数据确保代码只执行“类型安全”的操作。

4.序列化-反序列化。

5.允许GC跟踪对象的生存期。

1.2将托管模块合并成程序集

程序集:一个或多个模块/资源文件的逻辑性分组,其次,是重用、安全性以及版本控制的最小单元。它可以是一个可执行应用程序、也可以是个DLL



1.3加载公共语言运行时

CLR管理程序集代码的执行,所以必须安装.Net Framework

要知道是否安装.Net Framework,只需检查%SystemRoot%\System32目录中的MSCorEE.dll文件是否存在。

.Net Framework SDK提供了一个名为CLRVer.exe的命令执行程序,它能列出已经安装了的所有CLR版本

/platform开关选项对生成的模块的影响以及在运行时的影响



1.4执行程序集的代码

托管程序集同时包含元数据和IL,IL是与CPU无关的机器语言,但比大多数CPU机器语言要高级,还可以创建初始化对象、调用对象上的虚方法以及直接操作数组元素、捕获异常并抛出。综上所述可将IL视为一种面向对象的机器语言,IL可有ILAsm.exe的IL汇编器和ILDasm.exe的IL反汇编。 为了执行一个方法,首先必须把它的IL转换成本地CPU指令,这是CLR的JIT编译器的职责。

一个方法首次调用时发生的事情



第二次调用时发生的事情



Main函数第二次调用WriteLine时由于已对WriteLine的代码进行了验证和编译,所以会直接执行内存块中的代码,完全跳过JITCompiler函数(一旦进程终止,编译好的代码将被丢弃)。

还要注意的是,CLR的JIT会对本地代码进行优化,可能会花费一些时间,但性能更出色

有两个C#编译器的开关会影响代码的优化:/optimize和/debug

编译器开关设置
C#IL代码质量
JIT本地代码质量
/optimize-/debug-(默认)未优化有优化
/optimize-/debug(+/full/pdbonly)未优化未优化
/optimize+/debug(-/+/full/pdbonly)有优化未优化
使用/optimize-在C#编译器生成的未优化的IL代码中,将包含许多NOP(no-operation,空操作)指令,如果在调试期间,还可以在控制流程(如for,while,do,if,else,try,catch和finally语句块)上设置断点,使代码更易于调试,相反如果优化IL代码,则不能在上述流程中调试。
另外只有在指定/debug(+/full/pdbonly)开关的前提下编译器才会生成Program Database(PDB)文件

在Visual Studio中项目的

Debug(调试)配置对应的是/optimize-和/debug:full开关。

Release(发布)配置对应的是/optimize+和/debug:pdbonly开关

1.4.1 IL和验证

IL是基于栈的,在编译IL到本地指令的过程中,CLR会有一个验证的过程(包括方法正确数量的参数,正确的参数类型,返回值正确的使用,都有返回语句),在托管模块的元数据中包含了所有方法和类型信息。

1.4.2 不安全的代码

不安全代码允许直接操作内存地址,并可操作这些地址处的字节(通常在与非托管代码进行交互时,或提高对效率极高的算法时才需要这样做)

C#采用unsafe关键字,要求使用/unsafe编译器开关来编译

MS提供了一个PEVerify.exe的程序来检查程序集的所有方法是否采用不安全代码

1.5 本地代码生成器:NGen.exe

可以在一个应用程序安装到用户计算机上时,将IL代码编译成本地代码,由于代码在安装时已经编译好了,所以CLR的JIT无需编译IL代码,提升性能

两个应用场景:

加快应用程序的启动速度:运行时不需要花时间来编译

减小应用程序的工作集

NGen生成的文件存在一下问题:

没有只是产权保护

NGen生成的文件可能失去同步(并不是一劳永逸很容易失效)

较差的执行时性能

1.6 Framework 类库

利用这些程序集可以创建一部分应用

1.Webservice

2.WebForm

3.Windows应用程序

4.RIA(Silverlight)

5.Windows控制台应用程序

6.Windows服务

7.数据库存储过程

8.组件库

1.7 通用类型系统(CTS)

基本成员

Field、Method、Property、Event

成员访问修饰符(C#)

private:只能有同一个class类型中的其他成员访问

protected:可有派生类型访问,不管那些类型是否在同一个程序集

internal:成员可由同一个程序集的任何代码访问

protected internal:成员可有任何程序集中的派生类型访问,也可由同一程序集的任何类型访问

public:任何程序集的任何类型访问

理解“代码的语言”和“代码的行为”:

使用不同的语言,用于定义类型的语法也不同,无论使用哪一种语言,类型的行为都是完全一致的,因为最终是由CLR的CTS来定义类型的行为。

eg:CTS规定类型只能单继承,但C++语言允许多继承,CTS既不能接受、也不能操作这样的类型,所以就会报错。

CTS另一条规则:所有类型必须从预定义的System.Object类型继承,System.Object类型允许做下面事情:

1.比较两个实例的相等性

2.获取实例的哈希码

3.查询一个实例的真正类型

4.执行实例的浅拷贝

5.获取实例对象的当前状态的一个字符串表示

1.8 公共语言规范(CLS)

CLR集成了所有语言,允许在一种语言中使用由另一种语言创建的对象

C#中特性:[assembly:CLSCompliant(true)]

1.9 与非托管代码的互操作性

1.托管代码能调用DLL中的非托管函数

2.托管代码可以使用现有的COM组件(服务器)

3.非托管代码可以使用托管类型(服务器)

总结:首先编译器把源代码->托管模块(包含PE32头、CLR头、元数据、IL代码)

由于CLR是不和模块们一块工作的,它只爱程序集(assembly)

编译器不得不把托管模块们合并成->程序集

于是CLR和程序集在一起了,光在一起不行还是得干活的

CLR有以小弟叫JITCompiler,它对程序集中的IL转换成本地的CPU指令存到内存中
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: