1. CLR是如何工作的

    借用维基百科上的一副图来描述CLR的运行流程:

    从源代码到应用程序执行CLR主要做了以下工作:

    1. 将源代码编译成托管模块

      托管模块是一个标准的 32 位 Microsoft Windows 可移植执行体(PE32)文件,或者是一个标准的 64 位 Windows 可移植执行体(PE32+)文件,它们都需要 CLR 才能执行。一个托管模块主要包含一下几部分信息:

      • PE32货PE32+头

        这里描述了当前托管模块的基本信息,包括运行的Windows版本、文件类型、生成时间等。对于包含本地 CPU代码的模块,这个头包含了与本地 CPU 代码有关的信息。

      • CLR头

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

      • 元数据

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

      • IL (中间语言)代码

        编译器编译源代码时生成的代码。在运行时, CLR 将 IL 编译成本地 CPU 指令

    2. 将托管模块合并成程序集

      CLR 实际不和模块一起工作,而是和程序集一起工作的。可以从以下两点对程序集有一个初步的认识:

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

      在这一步,Windows 检查好 EXE 文件头,决定是创建 32 位、 64 位还是 WoW64 进程之后,会在进程的地址空间中 加载 MSCorEE.dll 的 x86,x64 或 IA64 版本。如果是 Windows 的 x86 版本,MSCorEE.dll 的 x86 版本在 C:\Windows\System32 目录中。如果是 Windows 的 x64 或 IA64 版本,MSCorEE.dll 的 x86 版本在 C:\Windows\SysWow64 目录中,64 位版本(x64 或者 IA64)则在 C:\Windows\System32 目录中(为了向后 兼容)。然后,进程的主线程调用 MSCorEE.dll 中定义的一个方法。这个方法初始化 CLR,加载 EXE 程序集, 然后调用其入口方法(Main)。随即,托管的应用程序将启动并运行。

    4. 执行程序集中的代码

      到目前为止,源代码已经被编译成二进制的IL并且包含在程序集中,而且被CLR加载。但是,直接执行运算的CPU来说二进制的IL还是太高级了,而且不同的CPU支持的指令集也有所差异。因此,CLR在这里还需要对已经编译好的IL再次编译,针对CPU版本生成可以直接运行的CPU指令,这个过程是由JIT(Just In Time)编译器完成的,可以称作“即时编译”。

      当第一次执行某个函数时,MSCorEE.dll 的JITCompiler函数会从程序集的元数据中获取该方法和方法的IL,并且分配一块内存地址,然后将IL编译成的本地代码放入这块内存,然后执行内存中的本地代码。

      当再次执行这个函数的时候,由于内存中已经存在JIT编译好的本地代码,因此不需要再次进行JIT过程,可以直接执行内存中的本地代码。 可以预知的结果是,这种情况下应用程序启动后第一次调用某个模块所花费的时间要比以后调用这个模块要稍微多一些。

      现在,通过本地代码生成技术,已经可以在编译阶段就根据计算机的的实际环境生成本地代码,这样以来就可以在运行时节省JIT编译的时间,提高程序的启动效率。这看起来是一个不错的功能,但是实际上运用的不是很广泛,主要是有一下限制:

      • 编译时生成的本地代码太过于依赖本地环境,一旦环境有变化 (包括操作系统更新、.Net Framework版本更新、CPU更换等),以前生成的本地代码都不再适用。
      • 编译时生成的本地代码必须要和程序集保持同步。
      • 编译时生成的本地代码不能像运行时JIT编译那样根据运行时的情况对代码进行优化。
  2. CL有哪些功能

  这里借用Jeffrey Richter的一段原话:

At first, I thought that the .NET Framework was an abstraction layer over the Win32 API and COM. As I invested more and more of my time into it, however, I realized that it was much bigger. In a way, it is its own operating system. It has its own memory manager, its own security system, its own file loader, its own error handling mechanism, its own application isolation boundaries (AppDomains), its own threading models, and more.

  虽然原文中Jeffrey Richter说的是.Net Framework,但很显然这些功能都是.Net Framework的核心组件CLR来提供的,正是CLR使.Net Framework并不是Win32 API和COM的一个抽象层,而是有了自己的"操作系统"(Jeffrey Richter的意思应该是在一定程度上,虚拟机也可以认为是一个小型的操作系统)。总结起来,CLR主要提供了一下功能:

  1. 基类库支持 (Base Class Library Support)
  2. 内存管理 (Memory Management)
  3. 线程管理 (Thread Management)
  4. 垃圾回收 (Garbage Collection)
  5. 安全性 (Security)
  6. 类型检查 (Type Checker)
  7. 异常处理 (Exception Manager)
  8. 即使编译 (JIT)

本系列主要围绕以上功能对CLR进行探讨。

【C#】CLR的更多相关文章

  1. 【SQL】CLR聚合函数什么鬼

    之前写过一个合并字符串的CLR聚合函数,基本是照抄MS的示例,外加了一些处理,已经投入使用很长时间,没什么问题也就没怎么研究,近日想改造一下,遇到一些问题,遂捣鼓一番,有些心得,记录如下. 一.杂项 ...

  2. 【转】CLR和JIT的理解、.NET反汇编学习

    CLR:通用语言运行时(Common Language Runtime)的简称,CLR是.NET框架的核心内容之一,可以把它看为一套标准资源,可以呗任何.NET程序使用.它包括:面向对象的编程模型.安 ...

  3. 【4opencv】CLR基本原理和如何运用于GOCW

    GOCW的重点和难点就在于Csharp调用OpenCV,其中的桥梁就是CLR,当然我们也有其他方法,但是CLR是一个比较新的.比较可靠的.关键是能用的桥梁.这里关于CLR的基本原理知识.如何用于GOC ...

  4. 【C#】CLR内存那点事(高级)

    对于这篇,不想再对值类型进行讨论,如要看值类型的内存怎么玩可以看一下(CLR内存那点事 初级),我们这篇主要讨论一下引用类型. 先来装备两个类 internal class Employee { pu ...

  5. 【C#】CLR内存那点事(string)

    string是比特殊的类,说引用类型,但不存在堆里面,而且String str=new String("HelloWorld")这样的重装也说没有的. 我们先来看一个方法 clas ...

  6. 【随笔】CLR:向头对象(Object Header)迈进一大步!!!

    前言 在我之前一篇随笔里(戳我),我们知道,一个引用类型的对象,包含了2个额外的开销,一个是头对象(object header),一个是MT.我们接下来看看头对象到底有多神秘... Object He ...

  7. 【随笔】CLR:.net的类型,内部到底长啥样?

    前言 一提到.net的类型,首当其冲的就是“引用类型”.“值类型”:我们在面试中,也会经常被问“来说说值类型和引用类型....”,这时候第一反应就是:“哎呀,这还不简单,值类型是传递的值的copy,值 ...

  8. 【译】CLR类型加载器设计

    前言 本文翻译自BotR中的一篇,原文链接 Type Loader Design ,可以帮助我们了解CLR的类型加载机制(注意是Type类型,而不是Class类),文中涉及到术语或者容易混淆的地方,我 ...

  9. 【BotR】CLR类型系统

    .NET运行时之书(Book of the Runtime,简称BotR)是一系列描述.NET运行时的文档,2007年左右在微软内部创建,最初目的是为了帮助其新员工快速上手.NET运行时:随着.NET ...

随机推荐

  1. Redhat下 Apache, php, mysql的默认安装路径

    apache: 如果采用RPM包安装,安装路径应在 /etc/httpd目录下 apache配置文件:/etc/httpd/conf/httpd.conf Apache模块路径:/usr/sbin/a ...

  2. Quartz.net 2.x 学习笔记03-使用反射加载定时任务

    将定时任务信息存储在XML文件中,使用反射加载定时任务 首先新建一个MVC的空站点,使用NuGet添加对Quartz.net和Common.Logging.Log4Net1213的引用,同时使用NuG ...

  3. python开发函数进阶:可迭代的&迭代器&生成器

    一,可迭代的&可迭代对象 1.一个一个的取值就是可迭代的   iterable#str list tuple set dict#可迭代的 ——对应的标志 __iter__ 2.判断一个变量是不 ...

  4. socket粘包现象加解决办法

    socket粘包现象分析与解决方案 简单远程执行命令程序开发(内容回顾) res = subprocess.Popen(cmd.decode('utf-8'),shell=True,stderr=su ...

  5. oracle 12c使用问题总结

    1.无法登录 安装完毕只能使用system和sys用户,用安装时配置的密码登录:不能使用默认密码 2.远程无法访问 1)检测服务器配置 lsnrctl status 看到(DESCRIPTION=(A ...

  6. KinderEditor编辑器 在Asp.Net中的使用

    KinderEditor编辑器的使用 分为简单的三步. 1:添加引用部分 <script src="/KinderEditor/kindeditor-min.js">& ...

  7. git用法小结(1)--建立远程仓库

    最近一直在学习使用git来管理自己的程序,总是今天东学一点,明天西凑一点,到用的时候,总是有些茫然不知所措. 在博客园里看见一篇老好的文章,教我们做笔记啦,但是做完笔记还是要记得总结哦! 来吧,让我们 ...

  8. 斐波那契数列,跳台阶(dp思想)

    一 . 斐波那契数列:1,1,2,3,5,8,13,21 即后一项是前两项的和. class Solution { private: ]; public: Solution() { memset(ar ...

  9. Physics Material

    [Physics Material] 1. The Physics Material is used to adjust friction and bouncing effects of collid ...

  10. java基础之JDBC三:简单工具类的提取及应用

    简单工具类: public class JDBCSimpleUtils { /** * 私有构造方法 */ private JDBCSimpleUtils() { } /** * 驱动 */ publ ...