zoukankan      html  css  js  c++  java
  • 第一章 CLR的执行模型

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

    CLR

      CLR(Common Language Runtime)公共语言运行时(也翻译为公共语言运行库)。故名思意,CLR是一个可由多种编程语言使用的“运行时”。核心功能(如内存管理,程序集加载,安全性,异常处理和线程同步)可由面向CLR的所有语言使用。 编译源代的过程:各种支持CLR的语言创建源代码文件。然后对应的编译器检查语法和分析源代码,最后生成托管模块:

     

    托管模块

      托管模块是标准的32位Microsoft Windows可移植执行体(PE32)文件,或者是标准的64位Windows 可移植执行体(PE32+)文件,它们都需要CLR才能执行。托管程序集总是利用Windows的数据执行保护(Data Execution Prevention,DEP)和地址空间布局随机化(Address Space Layout Randomization, ASLR),这个两功能旨在增强整个系统的安全性。 

    托管模块的各个部分

      PE32或PE32+头:标准Windows PE文件头,类型于“公共对象文件格式(Common Object File Format,COFF)头。如果整个头使用PE32格式,文件能在Windows的32位或64位版本上运行。如果这个头使用PE32+格式,文件只能在Windows的64位版本上运行。+这个头还标识了文件类型(GUI,CUI或者DLL),并包含一个时间标记文件的生成时间。对于只包含IL代码的模块,PE32(+)头的大多数信息会被忽略。如果是包含本机CPU代码的模块,这个头包含与本机CPU代码有关的信息。

      CLR 头:包含使这个模块成为托管模块的信息(可由CLR和一些实用程序进行解释)。头中包含要求的CLR版本,一些标志(flag),托管模块入口方法(Main 方法)的MethodDef 元数据token 以及模块的元数据,资源,强名称,一些标志及其他不太重要的数据项的位置/大小。

      元数据:每个托管模块都包含元数据表。主要有两种:一种表描述源代码中定义的类型和成员,另一种描述源代码引用的类型和成员。

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

      IL代码也叫托管代码,因为CLR管理它的执行。

      元数据简单地说是一个数据表集合,元数据是一些老技术的超集。COM的类型库和”接口定义语言,IDL“文件。

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

    程序集

      程序集是抽象概念,程序集是一个或多个模块/资源文件的逻辑性分组。程序集是重用,安全性以及版本控制的最小单元。在CLR的世界中,程序集相当于“组件”。编译器默认将生成的托管模块转换成程序集。

      清单:清单也是元数据表的集合。这些表描述了构成程序集的文件,程序集中的文件所实现的公开导出的类型以及与程序集关联的资源或数据文件。

    1.3 加载公共语言运行时 

       生产的每个程序集既可以是可执行应用程序,也可以是DLL(其中含有一组由可执行程序使用的类型)。最终由CLR管理这些程序集中的代码的执行。

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

    1.4 执行程序集的代码

      托管程序集同时包含元数据和IL。IL是与CPU无关的机器语言。IL能访问和操作对象类型,并提供了指令来创建和初始化对象,调用对象上的虚方法以及直接操作数组元素。提供抛出和捕捉异常的指令来实现错误处理。(面向对象的机器语言)

    JIT(just-in-time) 编译器

    为了执行方法,首先必须把方法的IL转换成本机CPU指令,

      调用方法:在方法执行前,CLR首先检测方法内引用的所有类型,这导致CLR分配一个内部数据结构来管理对引用类型的访问。这个内部数据结构中,定义的类型的每个方法都有一个对应的记录项。每个记录项都包含一个地址,根据此地址就可以找到方法的实现。在对这个结构初始时,CLR将每个记录项都设置成(指向)包含在CLR内部的一个未编挡函数(JITCompiler)。

    首次调用方法时,JITCompiler函数会被调用,函数负责将方法的IL代码编译成本机CPU指令。

      函数被调用时,它知道调用的是哪个方法,以及具体是什么类型定义了该方法。然后,JITCompilerh会在定义了(该类型的)程序集的元数据中查找被调用的方法IL。接着JITCompiler验证IL代码,并将IL代码编译成本机CPU指令。本机CPU指令保存到动态分配的内存块中。然后,JITCompiler回到CLR为类型创建的内部数据结构,找到与被调用方法对应的那条记录,修改最初对JITCompiler的引用,使其指向内存块(其中包含了刚才编译好的本机CPU指令)的地址。最后,JITCompiler函数跳转到内存块中的代码(方法的具体实现)。执行完毕返回继续执行后面的代码。

      如果在一次调用相同的方法,将跳过JITComiler函数,直接执行内存块中的代码。JIT编译器将本机CPU指令存储到动态内存中。这意味着一旦应用程序终止,编译好的代码也会被丢弃。

    托管代码相较于非托管代码的优势:

      JIT编译器能判断应用程序是否运行在Inter Pentium 4 CPU上,并生成相应的本机代码来利用Pentium4支持的任何特殊指令。

      JIT编译器能判段一个特定的测试在它运行的机器上是否总是失败。

      应用程序运行时,CLR可以评估代码的执行,并将IL重新编译成本机代码。

      用一个进程运行多个应用程序,可减少进程数,从而增强性能,减少所需要的资源,键壮性也没有丝毫下降。

    1.4.1 IL和验证

      IL基于栈。这意味着它的所有指令都要将操作数压入一个执行栈,并从栈弹出结果。

      IL指令是”无类型“的。 将IL编译成本机CPU指令时,CLR执行一个名为验证的过程。这个过程会检查高级IL代码,确定代码所做的一切都是安全的。

      Windows 的每个进程都有自己的虚拟地址空间。因为不能简单的信任一个应用程序的代码。将获得健壮性与稳定性:一个进程干扰不到另一个进程。

    1.4.2 不安全的代码

      不安全代码:允许直接操作内存地址,并可操作这些地址处的字节。

      风险:可能破坏数据结构,危害安全性,甚至造成新的安全漏洞。

      C#编译器要求所有方法使用 unsafe关键字。 使用/unsafe编译器开关编译源代码。

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

    NGen.exe工具,可以在应用程序安装到用户计算机上时,将IL代码编译成本机代码。

    优点:

    1.提高应用程序的启动速度。

    2.减少应用程序的工作集  

    缺点:

    1.生成的文件没有知识产权保护

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

    3.较差的执行时性能

    工作集

      指在进程的所有内存中,已映射的物理内存那一部分(即这些内存块全在物理内存中,并且CPU可以直接访问);进程还有一部分虚拟内存,它们可能在转换列表中(CPU不能通过虚地址访问,需要Windows映射之后才能访问);还有一部分内存在磁盘上的分页文件里。 

    1.6 Framework类库

    Framework Class Library, FCL是一组DLL程序集的统称。

    其他库:Windows Azure SDK,DirectX SDK

    可义创建应用程序:

    Web服务(Web Service)

    基于HTML的Web窗体/MVC应用程序(网站)

    “富”Windows GUI应用程序

    Windows控制台应用程序

    Windows服务

    数据库存储过程

    组件库

    1.7 通用类型系统

    由于类型是CLR的根本,所以Microsoft制定了一个正式的规范来描述类型的定义和行为,“通用类型系统”(Common Type System,CTS)

    公共语言基础结构(Common Language Infrastructure,CLI)

    CTS规范:一个类型可以包含零个或多个成员

    字段(Field):作为对象状态的一部分的数据变量。字段根据名称和类型来区分。

    方法(Method):针对对象执行操作的函数,通常会改变对象状态。

    属性(Property):对于调用者,属性看起来像是字段。但对于类型的实现者,属性看起来像是一(二)个方法(getter,setter)。

    事件(Event):事件在对象以及其他相关对象之间实现了通知机制。

    CTS还指定了类型可见性(public,assembly【Internal】)规则以及类型成员的访问规则

    private:成员只能由同一个类(class)类型中的其他成员访问。

    family:成员可有派生类型访问,不管那些类型是否在同一个程序集中。C# (Protected)

    family and assembly:成员可由派生类型访问,但这些派生类型必须在同一个程序集中定义。C#(无)

    assembly:成员可由同一个程序集中的任何代码访问。(Internal)

    family or assembly:成员可由任何程序集中的派生类型访问或同一程序集中的任何类型访问。(Protected internal)

    public:成员可由任何程序集中的任何代码访问。

    其他:

    比如规定一个类型只能从一个基类派生(单继承),

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

    1.8 公共语言规范

    Common Language Specification,CLS 公共语言规范 详细定义了一个最小功能集。

     

     每种语言都提供了CLR/CTS的一个子集以及CLS的一个超集(但不一定是同一个超集)

    CLR字段/方法对应的编程语言的各种构造

    在CLR中,类型的每个成员要么是字段(数据),要么是方法(行为)。

    类型成员 成员的类型 对应的编程语言构造
    AnEvent 字段 事件:字段名是AnEvent,类型是System.EventHandler
    .ctor 方法 构造器
    Finalize 方法 终结器
    add_AnEnvent 方法 事件的add访问器方法
    get_AProperty 方法 属性的get访问器方法
    get_Item 方法 索引器的get访问器方法
    op_Addition 方法 +操作符
    op_Equality 方法 ==操作符
    op_Inequality 方法 !=操作符
    remove_AnEvent 方法 事件的remove访问器方法
    set_AProperty 方法 属性的set访问器方法
    set_Item 方法 索引器的set访问方法

     

    .class

    .custom

    .AnEvent

    AProperty

    Item

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

    CLR支持三种互操作情形:

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

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

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

    每天学习一丢丢
  • 相关阅读:
    053-98
    053-672
    053-675
    1031 Hello World for U (20分)
    1065 A+B and C (64bit) (20分)
    1012 The Best Rank (25分)
    1015 Reversible Primes (20分)
    1013 Battle Over Cities (25分)
    1011 World Cup Betting (20分)
    1004 Counting Leaves (30分)
  • 原文地址:https://www.cnblogs.com/terry-1/p/9595563.html
Copyright © 2011-2022 走看看