天天看点

《CLR via C# 第四版》 读书笔记(一)CLR的执行模型

本人才疏学浅,如有错漏之处,还望指教一二。

名词解释:

①元数据(Metadata):可以简单理解为一个数据表集合,其中分为两种类型的数据,一种描述源代码的类型和成员,另一种描述源代码引用的类型和成员。元数据总是与包含IL代码的文件相关联,共同构成和程序代码相同的EXE、DLL文件。元数据的存在为程序编写和运行带来了很多的便利:“智能感知”技术会解析元数据,在编写程序时编译器会提示引用类型的成员和方法;避免了编译时对原生C、C++头和库的需求,在实现类型、成员的IL代码中已经包含了有关类型、成员的全部数据。

②中间语言(IL):有时也被称为托管代码,是介于程序代码和平台之间的第三方媒介。是一种与CPU无关的机器语言。

③公共语言运行时(CLR):是一个可以由多种语言使用的程序运行环境,他可以提供内存管理、程序集加载、异常处理和线程同步等服务,为托管代码提供平台。支持CLR的语言有C#、VB、F#、Python、PHP等大多数语言(Java不支持)。

④程序集(assembly):是CLR工作的最小单位,由托管模块组成。由于概念比较抽象,日后再详细介绍,暂时理解为一个文件(EXE、DLL)。

⑤MSCorEE.dll:作为电脑中是否安装Framework 的标志,存放在根目录下的System32文件夹中。

⑥JITter:JIT编译器,CLR的一个组件,用于IL的即时编译。

问题汇总:

①托管代码和非托管代码的区别?

      托管与非托管是针对于CLR定义的,简单的说,借助于CLR提供的一些服务来运行程序的代码为托管代码,而无需CLR提供服务就可以运行的代码称之为非托管代码。非托管代码先于托管代码产生,如早期由C++/C语言编写的直接对内存、操作系统操作的代码为非托管代码,他们可以直接获取操作系统提供的一些服务。

      托管代码是由编译器产生的,因此我们可以利用多种语言进行并行开发(生产中通常以引用包来发挥多种语言的优点),甚至可以直接编写IL代码,以提高程序质量和扩展功能,并且可以轻松的使用CLR提供的一系列服务,避免对内存的直接操作造成的一些问题。而非托管代码虽然不能借助于CLR提供的服务,但却也不受CLR的限制,可以直接对内存操作,调用操作系统提供的接口,较为灵活,但是也会提升错误概率。

②托管应用程序启动过程?

       Windows检查EXE文件头,决定创建32/64位进程,在进程地址空间加载MSCorEE.dll的32/64位版本,之后该进程的主线程调用MSCorEE.dll中的方法,这个方法初始化CLR、加载EXE程序集,再调用其入口方法(Main),随后托管应用程序启动并运行。

③执行程序集代码流程?

       在Main方法执行之前,CLR会检测出Main的代码引用的所有类型,CLR分配一个内部数据结构来管理对引用类型的访问,在这个内部数据结构中引用类型定义的所有方法都有一个记录项(entry),每个记录项都包含一个地址,根据这个地址可以找到该方法的实现。对这个结构初始化时,CLR将每个记录项都设置成指向CLR内部的一个未编档函数——JITCompiler,这个函数负责将方法的IL代码编译成本机CPU指令,本机CPU指令保存到动态分配的内存块中,之后JITCompiler返回CLR定义的内部数据结构,将该方法的记录项地址指向动态分配的内存块中,最后JITCompiler函数执行内存块中的代码,并返回到Main方法中。

       JIT编译器将本机CPU指令存储到动态内存中,一旦应用程序终止,编译好的代码也会被丢弃,所以再次运行应用程序的时候,JIT编译器必须再次将IL编译成本机指令。(这种方式会有一些性能损失,但与执行代码时间相比可以忽略不计),另外CLR的JIT编译器会对代码进行优化,优化后代码便很难进行单步调试,但效率和质量都有所提升。