第一章 CLR的执行模型

1 CLR的执行模型

术语:

ü  CLR:Common Language Runtime(程序exe或者dll执行时告诉Cpu做神马)

ü  IL:Intermediate Language

ü  Managed Module:托管模块

ü  GUI:Graphical User Interface图形用户界面Windows下

ü  CUI:Command line User Interface命令行模式的人机接口DOS下

ü  FCL:Framework Class Library

ü  CTS:Common Type System通用类型系统

ü  CLS:Common Language Specification公共语言规范

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

  • C#编译过程:C#语言编写的源码——C#编译器编译——托管模块(IL和元数据)
  • Microsoft面向CLR创建的编译器:C++,C#,VB,Jscript,J#,IL汇编器(其他部门也面向CLR创建了自己的编译器)
  • 托管模块:IL代码:编译器编译源代码时生成的代码

        元数据:源代码中及其引用的类和成员

        PE32头或PE32+头:

          1、标识在32位还是在64位Windows上运行

          2、  标识文件类型:CUI,GUI,DLL

          3、  记录文件生成时间

          4、  (解释:PE等是指可执行程序(EXE或DLL)文件格式,每种文件格式都有一些该可执行文件加载到内存中所需要的信息(如程序入口点等),这些信息被组织            为特定的数据结构,放在该可执行文件的开头部分,所以叫文件“头”。)

        CLR头:所要求的CLR版本,入口方法(Main),模块元数据、资源、强名称

  • 默认情况下C++不托管,但是可以开启托管开关

1.2将托管代码合并成程序集

  • 程序集:程序集是一个或多个模块\资源文件的逻辑性分组;是最小的重用、安全性及版本控制单元;在CLR的世界中,我们称之为“组件”。(比如一个项目有几个cs文件,最后生成一个dll这就是一个程序集,exe也可以)
  • CLR和程序集工作而不是模块
  • 项目只有一个文件(一个托管模块),且没有资源文件时,由C#编译器生成程序集。如果有多文件要合并到一个程序集,则要用到别的工具:AL.exe程序集连接器

 

1.3加载公共语言运行库

  • 补充知识:32位Windows与64位Windows

    简单的说x86代表32位操作系统 x64代表64位操作系统,所谓的32位64位应该是指表示每一个地址的位数比如000…..(共32位)00001表示一个地址

  • 程序集可以是Dll也可以是Exe,最终由CLR管理在这些程序集中代码的运行
  • 常规情况下,编写的代码在32位和64位操作系统上皆可正常运行,有些情况开发人员编写的代码需要在特定的windows版本上运行,通过在项目属性中设置目标平台进行,最终这个信息会被写入PE32或PE32+头中。编写32位程序可以在64位windows上运行,64位程序不可以在32位系统上运行。

 

  • 过程:

    1、  Windows检查EXE文件头,判断是创建32位进程还是64位进程还是WoW64进程

    2、  Windows在进程的地址空间中加载MSCorEE.dll的对应版本x86、x64、IA64版本

    3、  主线程调用MSCoreEE.dll内部定义的一个方法,此方法初始化CLR,加载EXE程序集然后调用其入口方法(Main)

    4、  被托管的应用程序启动并运行

1.4执行程序集的代码

  • 程序集的代码是托管类型的代码,是托管的exe或者dll,其代码是IL形式的。IL能访问和操作对象类型,能初始化对象。可以将IL想象成面向对象的机器语言。
  • CLR的一个特性:允许在不同编程语言间方便的切换,“混合语言编程”
  • 高级语言(C#)只是CLR的一个子集,IL则允许访问CLR的所有功能。
  • 执行程序集代码过程调用一个方法的流程:

    1、  在入口方法Main执行之前,CLR检测出Main代码引用的所有类型。CLR分配一个内部数据结构用于管理引用类型的访问,类型在Main中定义的每个方法都有一条对应记录      (地址),根据地址可以找到该方法的实现。

    2、  将每一个要执行的函数记录对应到一个函数,这个函数就叫JITCompiler

    3、  Main方法首次调用记录的一个方法时,调用JITCompiler函数

    4、  JITCompiler函数随后将IL代码编译成本地CPU指令(告诉CPU干嘛),本地CPU指令保存在一个动态分配的内存块中

    5、  JITCompiler回到CLR为类型创建的内部数据结构,找到与被调用方法对应的那条记录,将调用它的引用转换为内存块的地址

    6、  JITCompiler跳到内存块中的代码。这些代码是方法的具体实现

    7、  返回Main中代码

    8、  第二次执行同一个方法时则不调用JITCompiler了而直接调用内存块中的(已经编译好的CPU指令)指令。

  • C++编译好的代码是非托管代码,C#编译好的代码是托管代码。区别就是C++代码直接就是CPU指令了,二C#代码是IL中间代码,还要在运行时经过JIT编译器编译成CPU指令。这样势必会影响C#程序运行的速度,由于其JIT编译时还会分配动态内存所以还会占用一些内存。但是作者说JIT编译器做了很多优化,而且有一些非托管代码没有的优势如

    1、  JIT能判断CPU,所以可以利用CPU的特殊指令

    2、  JIT可以判断一个特定的测试在运行它的机器上是否总是失败,从而减少编译。??

    3、  CLR可以评估代码的执行,减少不正确的分支??

  • NGen.exe将程序集的IL代码编译成本地代码
  • 将IL编译成本地CPU指令时,CLR会执行一个名为“验证”的过程。这个过程会检验高级IL代码,确定代码所做的一切都是安全的。如:参数,返回值,等
  • 托管代码的另一个好处:因为有验证过程,一个地址空间可以运行多个托管程序,所以能在单个OS进程中运行多个应用程序,从而减少系统进程数提升性能。
  • 每个多团的应用程序都叫做一个AppDomain。
  • 不安全的代码允许直接操作内存地址,而且允许在这些地址处操作多个字节。
  • C#要求不安全代码加入unsafe关键字,而且要打开/unsafe编译器开关
  • IL与知识产权保护:

  1.4.1 IL和验证

    • 将IL编译成本地CPU指令时,CLR会执行一个名为“验证”的过程。这个过程会检验高级IL代码,确定代码所做的一切都是安全的。如:参数,返回值,等
    • 托管代码的另一个好处:因为有验证过程,一个地址空间可以运行多个托管程序,所以能在单个OS进程中运行多个应用程序,从而减少系统进程数提升性能。
    • 每个多团的应用程序都叫做一个AppDomain。

 

  1.4.2 不安全的代码

  • 不安全的代码允许直接操作内存地址,而且允许在这些地址处操作多个字节。
  • C#要求不安全代码加入unsafe关键字,而且要打开/unsafe编译器开关
  • IL与知识产权保护:

    1、  第三方混淆器

    2、  非托管模块实现保密算法,CLR实现托管与非托管之间的通信

    3、  微软未来:数字资产管理铲平

*1.5本地代码生成器

  • NGen.exe工具好处:

    1、  加快应用程序启动速度

    2、  减小应用程序的工作集

  • 缺点:

    1、  没有知识产权保护

    2、  NGen生成的文件可能失去同步

    3、  交叉的加载时性能

    4、  较差的执行性能

1.6 Framework类库入门

  • FCL:一系列程序集的统称

1.7通用类型系统

  • CLS:描述类型的定义以及其行为方式

    1、  一个类型可以包括另个或者多个成员

    2、  指定了类型可视性规则和类型成员的访问规则

    3、  还定义了对类继承、虚方法、对象生存周期等进行管理的规则

    4、  所有类型最终必须从预定义类型System.Object继承

1.8 公共语言规范

  • 微软定义了一个最小特征集:CLS,这个特征集实际上就是所有语言规范的一个交集。
  • Private成员可以不符合CLS因为外面不可访问,如果想在程序集外用另一种语言访问程序及内成员,则该类型的public和protected成员必须符合CLS
  • 使用[assembly: CLSCompliant(true)]标志程序集,告诉编译器检查该程序集的CLS相容性。
  • CLS规则精简:CLR中一个类型的每个成员要么是字段(数据),要么是方法(行为),高级语言为了简化编程会提供如枚举,数组,属性,索引,委派,事件,构造器,终结器,操作符重载,转换操作符等概念,但是编译器会在编译源代码为IL时把他们一致转换为方法和字段。可以在ILDasm.exe中查看。这样一种归纳可以使得各种语言都能访问这种结构。
  • 不符合CLS的代码,在另一种语言里面是没法使用的。

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

  • CLR支持托管与非托管代码间三种类型的互操作:  

    1、  托管代码能调用DLL中的一个非托管函数

    2、  托管代码可以使用现有的COM组件

    3、  非托管代码可以使用托管类型

你可能感兴趣的:(LR)