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

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

可用支持CLR的任何语言创建源代码文件,然后用对应的编译器检查语法和分析源代码。无论选择哪个编译器,结果都是托管模块(managed module)。托管模块是标准的32位Microsoft Windows可移植执行体(PE32)文件,或者是标准的64位Windows可移植执行体(PE32+)文件,他们都需要CLR才能执行。(注:PE是Portable Executable(可移植执行体)的简称)

本机代码编译器(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实际不和模块工作。它和程序集工作。

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

  

  图中一些托管模块和资源(或数据)文件准备交由一个工具处理。工具生成代表文件逻辑分组的一个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或者"即时")编译器的职责。

就在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%内容来自书本原文。把知识要点搬运到这里,只是为了方便本人复习、查阅)

CLR via C#读书笔记一:CLR的执行模型的更多相关文章

  1. CLR via C# 读书笔记-21.托管堆和垃圾回收

    前言 近段时间工作需要用到了这块知识,遂加急补了一下基础,CLR中这一章节反复看了好多遍,得知一二,便记录下来,给自己做一个学习记录,也希望不对地方能够得到补充指点. 1,.托管代码和非托管代码的区别 ...

  2. [Clr via C#读书笔记]Cp1CLR执行模型

    Cp1CLR执行模型 本章的概念点 CLR=Common Language Runtime 内存管理,程序集加载,安全性,异常处理和线程同步.CLR是基础,支持着面向它的各种语言.各种语言会被对应的编 ...

  3. CLR via C# 读书笔记---常量、字段、方法和参数

    常量 常量是值从不变化的符号.定义常量符号时,它的值必须能在编译时确定.确定后,编译器将唱两只保存在程序集元数据中.使用const关键字声明常量.由于常量值从不变化,所以常量总是被视为类型定义的一部分 ...

  4. Clr Via C#读书笔记---I/O限制的异步操作

    widows如何执行I/O操作      构造调用一个FileStream对象打开一个磁盘文件-----FileStream.Read方法从文件中读取数据(此时线程从托管代码转为本地/用户模式代码)- ...

  5. Clr Via C#读书笔记---计算限制的异步操作

    线程池基础 1,线程的创建和销毁是一个昂贵的操作,线程调度以及上下文切换耗费时间和内存资源. 2,线程池是一个线程集合,供应你的用程序使用. 3,每个CLR有一个自己的线程池,线程池由CLR控制的所有 ...

  6. Clr Via C#读书笔记---CLR寄宿和应用程序域

    #1 CLR寄宿: 开发CLR时,Microsoft实际是将他实现成包含在一个dll中的COM服务器.Microsoft为CLR定义了一个标准的COM接口,并为该接口和COM服务器分配了GUID.安装 ...

  7. Clr Via C#读书笔记---程序集的加载和反射

    #1 加载程序集 Assembly.Load: public class Assembly { public static Assembly Load(AssemblyName assemblyRef ...

  8. Clr Via C#读书笔记---垃圾回收机制

    #1 垃圾回收平台的基本工作原理: 访问一个资源所需的具体步骤: 1)调用IL指令newobj,为代表资源的类型分配内存.在C#中使用new操作符,编译器就会自动生成该指令.2)初始化内存,设置资源的 ...

  9. Clr Via C#读书笔记---线程基础

    趣闻:我是一个线程:http://kb.cnblogs.com/page/542462/ 进程与线程 进程:应用程序的一个实例使用的资源的集合.每个进程都被赋予了一个虚拟地址空间. 线程:对CPU进行 ...

  10. CLR via C# 读书笔记 6-2 不同AppDomain之间的通信 z

    跨AppDomain通信有两种方式 1.Marshal By reference : 传递引用 2.Marshal By Value : 把需要传递的对象 通过序列化反序列化的方式传递过去(值拷贝) ...

随机推荐

  1. flask 的管理模块的功能add_template_global、send_from_directory

    add_template_global方法 全局模板函数 add_template_global 装饰器直接将函数注册为模板全局函数. add_template_global 这个方式是自定义的全局函 ...

  2. 便利的操作plist文件

    便利的操作plist文件 升级iOS9了,网络被强制切换成https了,你需要更新你的plist的文件才能够支持http,正常的做法是这样子的: 过程是不是挺繁琐的呢?如果你新建的另外一个工程,里面还 ...

  3. 使用YXHUD

    使用YXHUD 这是本人自己设计的一个类,但功能很不完善,先看看效果: 源码: YXHUD.h 与 YXHUD.m // // YXHUD.h // UILabel // // Created by ...

  4. Provisional headers are shown

    问题: Chrome请求出现"Provisional headers are shown": 原因: 这种一般是由于浏览器端的插件或客户端的软件对请求进行了拦截:我们出现的情况,是 ...

  5. Hadoop HBase概念学习系列之物理视图(又名为物理模型)(九)

    虽然,从HBase的概念视图来看,每个表格是由很多行组成的,但是在物理存储上面,它是按照列来保存的,这一点在进行数据设计和程序开发的时候必须牢记. 在物理存储上面,它是按照列来保存的 需要注意的是,在 ...

  6. November 28th 2016 Week 49th Monday

    You only live once, but if you do it right, once is enough. 年华不虚度,一生也足矣. One today can win two tomor ...

  7. * args 和 **kwargs

    def func(*args, **kwargs): print(args,kwargs) func("对", "哦",o=4, k=0) 结果---> ...

  8. ES6中map和set用法

    ES6中map和set用法 --转载自廖雪峰的官方网站 一.map Map是一组键值对的结构,具有极快的查找速度. 举个例子,假设要根据同学的名字查找对应的成绩,如果用Array实现,需要两个Arra ...

  9. 团队作业1——团队展示&教辅宝

    1.队名:PHILOSOPHER 2.队员学号: [组长]金盛昌(201421122043).刘文钊(20142112255).陈笑林(201421122042). 张俊逸(201421122044) ...

  10. [DAViCHi/SeeYa/T-ARA][원더우먼][Wonder Woman]

    歌词来源:http://music.163.com/#/song?id=5371229 作曲 : 赵英秀 [作曲 : 赵英秀] [作曲 : 赵英秀] 作词 : K-Smith [作词 : KSmith ...