【前言】

  • 方法执行前,CLR 会检测方法内代码引用的所有类型。同时 CLR 会分配一个内部数据结构,用来管理对所有引用的类型的访问。
  • 首次执行方法时,托管程序集会把 IL 转换成本地 CPU 指令,并将其存储在一个动态分配的内存块中。 这是 CLR 的 JIT(just-in-time)编译器的功能。
  • 在应用程序终止前,如果再调用同一个方法,会直接执行存储在动态分配内存块里的 CPU 指令。

【图解】

1.当 “首次” 执行方法时,实际发生的事情如下图所示

就在 Main 方法执行之前,CLR 会检测出 Main 的代码引用的所有类型。这导致 CLR 分配一个内部数据结构,它用于管理对所有引用的类型的访问。如上图所示,Main 方法引用了一个 Console 类型,这导致 CLR 分配一个内部结构。在这个内部数据结构中,Console 类型定义的每个方法都有一个对应的记录项。每个记录项都容纳了一个地址,根据此地址即可找到方法的实现。对这个结构进行初始化时,CLR 将每个记录项都设置成(指向)包含在 CLR 内部的一个未文档化的函数。我们将这个函数称为 JITCompiler。

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

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

2.方法 “再次” 执行时,实际发生的事情如下图所示

第二次调用 WriteLine。这次由于已对 WriteLine 的代码进行了验证和编译,所以会直接执行内存块中的代码,完全跳过 JITCompiler 函数。 WriteLine 方法执行完毕之后,会再次返回 Main。

注意:JIT 编译器将本地 CPU 指令存储到动态内存中。一旦应用程序终止,编译好的代码也会被丢弃。所以,如果将来再次运行应用程序,或者同时启动应用程序的两个实例(使用两个不同的操作系统进程),JIT 编译器必须再次将 IL 编译成本地指令。

读经典——《CLR via C#》(Jeffrey Richter著) 笔记_方法执行的更多相关文章

  1. 读经典——《CLR via C#》(Jeffrey Richter著) 笔记_发布者策略控制

    在 读经典——<CLR via C#>(Jeffrey Richter著) 笔记_高级管理控制(配置)中,是由程序集的发布者将程序集的一个新版本发送给管理员,后者安装程序集,并手动编辑应用 ...

  2. 读经典——《CLR via C#》(Jeffrey Richter著) 笔记_通过ILDasm.exe查看编译器如何将类型及其成员编译成元数据

    [实例代码] using System; public sealed class SomeType //-------------1 { //嵌套类 private class SomeNestedT ...

  3. 读经典——《CLR via C#》(Jeffrey Richter著) 笔记_基元类型(二)

    [基元类型推荐] 推荐直接使用 FCL 类型. [理由] 编码时不至于困惑string与String的使用.由于C#的stirng(一个关键字)直接映射到System.String(一个 FCL 类型 ...

  4. 读经典——《CLR via C#》(Jeffrey Richter著) 笔记_基元类型(一)

    [概念] 编译器直接支持的数据类型 [C#基元类型与对应的 FCL 类型] C#基元类型 FCL 类型 说明 sbyte System.Sbyte 有符号8位值 byte System.Byte 无符 ...

  5. 读经典——《CLR via C#》(Jeffrey Richter著) 笔记_高级管理控制(配置)

    一个应用程序的XML配置文件示例: <?xml version="1.0"?> <configuration> <runtime> <as ...

  6. 读经典——《CLR via C#》(Jeffrey Richter著) 笔记_运行时解析类型引用

    public sealed class Program{ public static void Main() { System.Console.WriteLine("Hi"); } ...

  7. 读经典——《CLR via C#》(Jeffrey Richter著) 笔记_元数据

    1.元数据简介 全称:metadata 属性:数据表集合 产地:面向 CLR 的编译器在托管模块中生成 2.元数据内部结构及与托管模块的关系 [概述] 托管模块中包含着元数据,元数据是由一组数据表组成 ...

  8. 读经典——《CLR via C#》(Jeffrey Richter著) 笔记_友元程序集

    [应用场景] 程序集A访问程序集B定义的Internal访问类型的类的成员. [使用方式] 在构建程序集B的时候,引入System.Runtime.CompilerServices,以此来添加Inte ...

  9. 读经典——《CLR via C#》(Jeffrey Richter著) 笔记_类型的各种成员

    [Class中,可能包含的成员] 常量, 字段, 实例构造器, 类型构造器, 方法, 操作符重载, 转换操作符, 属性, 事件, 类型(Class)

随机推荐

  1. Linux之Ubuntu环境配置(一)

    Linux下的搜狗输入法安装: 1.搜狗官网下载Linux64bit版本文件,默认在/home/username/Downloads目录下. 2.cd /home/username/Downloads ...

  2. 登陆Oracle出现错误java.lang.exception

    出现错误时登录企业管理器时出现的界面 出现这种错误一般是因为没有设置时区,一般默认的是agentTZRegion=GMT,也就是GMT.所以大家只要设置了这个东西,然后重新启动dbconsole就可以 ...

  3. 为Docker镜像添加SSH服务

    一.基于commit命令创建 1. 首先下载镜像 $ docker run -it ubuntu:16.04 /bin/bash 2. 安装SSH服务 #更新apt缓存 root@5ef1d31632 ...

  4. oracle DCL-(grant、revoke )

    1.授权GRANT <权限列表> to <user_name>; 2.收回权限REVOKE <权限列表> from <user_name>

  5. js实现鼠标拖拽

    主要原理: 1.当鼠标按下时,记录鼠标坐标,用到的是 onmousedown: 2.当鼠标移动时,计算鼠标移动的坐标之差,用到的是 onmousemove: 3.当鼠标松开时,清除事件,用到的是 on ...

  6. conda 添加bioconda源,创建/删除/重命名环境

    1.conda安装 在https://repo.continuum.io/miniconda/选择conda版本 wget "https://repo.continuum.io/archiv ...

  7. Entity Framework Tutorial Basics(16):Linq-to-Entities Projection Queries

    Linq-to-Entities Projection Queries: Here, you will learn how to write LINQ-to-Entities queries and ...

  8. auto和register关键字

    关键字概述 很多朋友看到这儿可能会有疑问,往往其它讲C语言的书籍都是从HelloWorld,数据类型开始C语言学习的,为什么我们要从C语言的关键字开始呢?关于这点,我有两点需要说明: 本章节面向的读者 ...

  9. C++笔记--类型和声明

    布尔量 Eg: bool b1=a==b;//这个例子中,=是赋值,==是判断是否相等,所以先是判断是否相等,a如果等于b,b1的值就是true,否则就是false了 Bool经常被用作检查某些条件是 ...

  10. SQLite操作

    创建有主键的表: create table test (pkey varchar(16) primary key, value varchar(10)); 创建有复合(即key由多个字段联合组成)主键 ...