将源代码编译成托管模块
公共语言运行时CLR
公共语言运行时(Common Language Runtime,CLR)是一个可由多种编程语言使用的“运行时”。它负责在执行时管理代码,提供内存管理、异常处理、线程管理等核心服务,同时又确保代码的安全性和准确性。
源码的编译过程
源码的编译过程如图所示,使用支持CLR的语言创建源代码文件,然后通过相应的编译器对源码进行语法检查和分析,生成托管模块。托管模块主要由4部分组成:PE32或PE32+头、CLR头、元数据、IL代码。
托管模块的组成部分及说明:
组成部分 | 说明 |
---|---|
PE32或PE32+头 | 标准的Windows PE文件头,标识出了文件使用何种格式、文件类型、生成时间等信息 |
CLR头 | 包含使用这个模块成为托管模块的信息 |
元数据 | 主要有两种表:描述源代码中定义的类型和成员;描述源代码引用的类型和成员 |
IL代码 | 编译器编译源代码时生成的代码 |
##将托管模块合并成程序集
CLR实际不和托管模块工作,它和程序集工作。程序集是一个或多个模块/资源文件的逻辑性分组。程序集是重用、安全性以及版本控制的最小单元。下图展示了一些托管模块和资源文件交由一个工具处理,生成代表文件逻辑分组的一个PE32(+)文件的过程。
##加载公共语言运行时
Windows检查可执行文件的文件头,决定创建32位还是64位进程,在进程地址空间加载对应版本的MSCorEE.dll文件,调用MSCorEE.dll中的方法初始化CLR,加载程序集,随后调用其入口方法,启动并运行托管应用程序。
##执行程序集的代码
为了执行程序集的代码,首先要把方法的IL转换为本机CPU指令。这是CLR的JIT(just-in-time)编译器的职责。下图展示了方法调用的执行过程。
执行步骤:
- 在Main方法执行之前,CLR会检测出Main的代码引用的所有类型。使CLR分配一个内部数据结构来管理对引用类型的访问(II),在这个数据结构中,Console类定义的每个方法都有一条对应的记录,每条记录都含有一个地址,根据此地址即可找到方法的实现。对这个结构初始化时,CLR将每个记录项都设置成包含在CLR内部的一个未编档函数,我们称之为JITCompiler。
- Main方法首次调用WriteLine时,JITCompiler函数被调用,执行III中的操作。
- 代码执行完毕后,回到Main中,继续执行下一条语句。
- 由于步骤2中已经对WriteLine的代码进行了验证和编译,所以会直接执行内存块中的代码,完全跳过JITCompiler函数。
由以上步骤可知:
- 方法仅在第一次被调用时才有一些性能损失。以后的调用都以本机代码的形式全速运行。
- JIT编译将本机CPU指令保存在动态内存中。也就是说,一旦应用程序关闭,编译好的代码也会丢失。
##本机代码生成器:NGen.exe
使用.NET Framework提供的NGen.exe工具,可以在应用程序安装时,将IL代码编译成本机代码。
优点:
- 提高应用程序的启动速度。因为已经编译成本地代码,运行时不再需要花费时间编译IL代码
- 减小应用程序的工作集。NGen.exe将IL编译成本机代码,并将这些代码保存到单独的文件夹中,该文件通过“内存映射”的方式,同时映射到多个进程地址空间中,使代码得到共享,避免每个进程都需要一份单独的代码拷贝
缺点:
- 没有知识产权保护
- NGen生成的文件可能失去同步
- 较差的执行时性能
##Framework类库
.NET Framework包含Framework类库(Framework Class Library,FCL)。FCL是一组程序集的统称。以下是常用的FCL命名空间:
命名空间 | 内容说明 |
---|---|
System | 包含每个应用程序都要用到的所有基本类型 |
System.Data | 包含用于和数据库通信以及数据处理的类型 |
System.IO | 包含用于执行流I/O以及浏览目录/文件的类型 |
System.Net | 包含进行低级网络通信,并与一些常用Internet协议协作的类型 |
System.Runtime.InteropService | 包含允许托管代码访问非托管操作系统平台功能 |
System.Security | 包含用于保护数据和资源的类型 |
System.Text | 包含处理各种编码文本的类型 |
System.Threading | 包含用于异步操作和同步资源访问的类型 |
System.Xml | 包含用于处理XML架构和数据的类型 |
##通用类型系统
CLR一切围绕类型展开。通用类型系统(Common Type System,CTS)是Microsoft制定的一套用来描述类型的定义和行为的规范。
通用类型系统的功能:
- 建立用于跨语言执行的框架
- 提供面向对象的模型,支持.NET平台上实现各种语言
- 定义处理类型时所有语言都必须遵守的一组规则
- 提供包含应用程序开发中使用的基本基元数据类型的库
CTS规范规定,一个类型可以包含零个或多个成员(字段,方法,属性,事件)。另外,CTS还指定了类型的可见性规则以及类型成员的访问规则。除此之外,CTS还为类型基础、虚方法、对象生存期等定义了响应的规则。
##公共语言规范
要创建从其他编程语言中访问的类型,只能从自己的语言中挑选其他语言都支持的功能。Microsoft定义了公共语言规范(Common Language Specification,CLS),它详细定义了最小的功能集。
CLS定义的是CLR/CTS功能的一个子集。
与非托管代码的互操作性
CLR支持三种互操作情形:
- 托管代码能调用DLL中的非托管函数
- 托管代码可以使用现有COM组件
- 非托管代码可以使用托管类型