CLR via C#读书笔记一:CLR的执行模型

 

CLR(Common Language
Runtime)
公共语言举办时是一个可由多种编程语言使用的“举行时”。

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

可用协理CLR的另外语言创造源代码文件,然后用相应的编译器检查语法和分析源代码。无论选用哪个编译器,结果都是托管模块(managed
module)。
托管模块是正规的32位Microsoft
Windows可移植执行体(PE32)文件,或者是正式的64位Windows可移植执行体(PE32+)文件,他们都亟需CLR才能履行。(注:PE是Portable
Executable(可移植执行体)的简称)

图片 1图片 2

本机代码编译器(native code
compilers)生成的是面向特定CPU架构(比如x86,x64或ARM)的代码。相反,每个面向CLR的编译器生成的都是IL(中间需要)的代码。

   除了生成IL面向CLR的编译器还要在每个托管模块中生成完全的元数据(metadata)。元数据简单地说就是一个数据表集合。一些数据表描述了模块中定义了什么样(比如类型及其成员),另一部分叙述了模块引用了怎么(比如导入的品类及成员)。

  Microsoft的C++编译器默认生成包含非托管(native)代码的exe/dll模块,并在运转时操作非托管数据(native内存)CLR即可执行。然则,通过指定/CLR命令行开关,C++编译器就能生成包含托管代码的模块。当然,最后用户必须安装CLR才能履行这种代码。在面前提到的装有Microsoft编译器中,C++编译器是无比的,只有它才同意开发人士同时写托管和非托管代码,并扭转到同一个模块中。它也是绝无仅有允许开发人士在源代码中而且定义托管和非托管数据类型的Microsoft编译器。

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

  CLR实际不和模块工作。它和程序集工作。

  首先,程序集是一个或六个模块/资源文件的逻辑分组。其次,程序集是录取、安全性以及版本控制的细小单元。

  图片 3

  图中有的托管模块和资源(或数额)文件准备交由一个工具处理。工具生成代表文件逻辑分组的一个PE32(+)文件。实际暴发的事体是,这多少个PE32(+)文件包含一个名为清单(mainfest)的数据块。清单也是元数据表的集纳。这个表描述了整合程序集的文件、程序集中的文件所实现的公然导出的门类以及与程序集关联的资源或数据文件。(注:所谓公开导出的品种,就是先后集中定义的public类型,它们在程序集内部外部均可见。)

   编译器默认将扭转的托管模块转换成程序集。也就是说,C#编译器生成的是包含清单的托管模块。清单指出程序集吸由一个文书构成。对于只有一个托管模块而且无资源(或数额)文件的类别,程序集就是托管模块,生成过程中无需举办此外额外的步调。然则,假设期望将一组文件合并到程序集中,就非得撑握更多的工具(比如程序集链接器AL.exe)及其命令行选项。

  • 加载公共语言运行时CLR

  可执行文件(exe)运行时,Windows检查EXE文件头,决定是创建32位仍然64位过程之后,会在经过地址空间加载MSCorEE.dll的x86,x64或ARM版本。假假诺Windows的x86或ARM版本,MSCorEE.dll的x86版本在%SystemRoot%\System32目录中。如果是Windows的x64版本,MSCorEE.dll的x86版本在%SystemRoot%\SysWow64目录中,64位版本则在%SystemRoot%\System32索引中(为了向后十分)。然后,进程的主线程序调用MSCorEE.dll中定义的一个措施。这么些点子初步化CLR,加载EXE程序集,再调用其输入方法(Main)。随即,托管应用程序启动并运行。(PS:微软在64位系统军长所有拍卖32位程序的工具都置身SysWow64目录下,Wow就是Windows
on
Windows的趣味。而System32目录是拍卖64位程序的。还叫32,只是延续了原先的叫法,其实应该是64)

  • 执行顺序集的代码  

  开发人员一般用c#,VB等高等语言举行编程。它们的编译器将生成IL。然则,和其他任何机器语言一样,IL也能动用汇编语言编写,Microsoft甚至专门提供了名为ILAsm.exe的IL汇编器和名为ILDasm.exe的IL反汇编器。注意,高级语言平时只公开了CLR全体功力的一个子集。可是IL汇编语言允许开发人士访问CLR的整整效果。要领悟CLR具体提供了什么效能,唯一的措施是阅读CLR文档。

  为了举办办法,首先必须把办法的IL转换成本机(navive)CPU指令。这是CLR的JIT(just-in-time或者”即时”)编译器的任务。

图片 4

就在Main方法执行往日,CLR会检测出Main的代码引用的具有品种。这致使CLR分配一个内部数据结构来管理对引用类型的拜访。图中Main方法引用了一个Console类型,导致CLR分配一个内部结构。在这个里面数据结构中,Console类型定义的每个方法都有一个相应的记录项。每个记录项都包含一个地方。依据此地方即可找到办法的贯彻。对这一个社团起始化,CLR将各类记录项都设置成(指向)包含在CLR内部的一个未编档函数。我将该函数称为JITCompiler。

Main方法第一次调用WriteLine时,JITCompiler函数会被调用。JITCompiler函数负责将艺术的IL代码编译成本机CPU指令。由于IL是”即时“(just
in time)编译的,所以一般将CLR的这几个组件称为JITter或者JIT编译器。

JITCompiler函数被调用时,它知道是要调用的是哪些方法,以及具体是咋样类型定义了该措施。然后,JITCompiler会在概念(该项目标)程序集的元数据中找找被调用方法的IL。接着JITCompiler验证IL代码,并将IL代码编译成本机CPU指令。CPU指令保存到动态分配的内在块中。然后
,JITCompiler回到CLR为品种创设的其中数据结构,找到与被调用方法对应的那条记下,修改最初对JITCompiler的引用,使其针对性内在块(其中蕴藏了刚刚编译好的本机CPU指令)的地址。最终,JITCompiler函数中跳转到内存块中的代码。这么些代码正是WriteLine方法(获取单个String参数的百般版本)的现实贯彻。代码执行完毕并赶回时,会重临Main中的代码,并像过去相同继续执行。

现行,Main要第二次调用WriteLine。这五遍,由于已对WriteLine的代码进行了注明和编译,所以会一贯实施内存块中的代码,完全跳过JITCompiler函数。WriteLine方法执行完毕后,会另行回到Main。

  •  IL和验证

  将IL编译成本机CPU指令时,CLR执行一个名为验证(verification)的历程。

  CLR确实提供了在一个操作系统中施行之个托管应用程序的能力。每个托管应用程序都在一个AppDomain中进行。每个托管EXE文件默认都在它和谐的单独地址空间中运作,这个地点空间只有一个AppDomain。可是,CLR的宿主进程(比如IIS或者Microsoft
SQL Server)可控制在一个历程中运作多少个AppDomain。

  • 本机代码生成器:NGen.exe

  行使用.NET
Framework提供的NGen.exe工具,可以在应用程序安装到用户的电脑上时,将IL代码编译成本机代码。由于代码在装置时已经编译好,所以CLR的JIT编译器不需要在运转时编译IL代码,这促进进步应用程序的性质。NGen.exe能在偏下两种意况下发布紧要效率。

  1提升应用程序的启动速度

  2缩小应用程序的办事集(所谓工作集,是指在过程的享有内存中,已映射的大体内存这有些(即那么些内存全在情理内存中,CPU可以一贯访问);进程还有一部分虚拟内存,它们或者在转移列表中(CPU不可能经过虚拟地址访问,需要Windows映射之后才能访问);还有部分内存在磁盘上的分页文件里。)

  NGen.exe生成的文书有以下问题

  1没有文化产权爱护

  2NGen生成的文书或者错过同步

  3较差的施行时性能

  • Framework类库

  FCL(Framework Class
Library)

  • 通用项目系统

  Microsoft制定了一个正式规范来描述类型的定义和行为,这就是“通用项目系统”(Common
Type System,CTS)。

  • 集体语言专业

  要创制很容易从此外编程语言中访问的系列,只可以从自己
的语言中甄选其他具有语言都协助的效率。为了在这么些下面提供救助,Microsoft定义了“公共语言专业”(Common
Language
Specification,CLS
),它详细定义了一个微细效率集。任何编译器只有援助那多少个效用集,生成的门类才能配合由其余符合CLS、面向CLR的言语生成组件。
  (个人的明白:CLS是为了不同编程语言之间交互调用而设计的,如若只用一种语言,就无须考虑CLS的业内)

  (说明:文中99%内容来自书本原文。把文化要点搬运到此处,只是为着方便自己复习、查阅)

相关文章