JIT(just in time)编译器

接下来的会讲到方法的调用,这里先讲下JIT编译器。以CLR书中的代码为例(手打...)。以Main方法为例:

static void Main(){
Console.WriteLine("Hello");
Console.WriteLine("XiaoCong");
}
  1. 首先CLR会检测到Main方法中引用了一个Console类型,然后CLR会为其分配一个内部结构。
  2. 内部结构中每个方法都对应一个记录项,记录项中都容纳一个地址,根据此地址可以找到方法的实现。
  3. 对结构进行初始化时,会把记录项指向JITCompiler函数。

  4. 当第二次执行wirteLine时,由于第一次已经进行了验证和编译,所以跳过JIT函数,直接执行内存块中的代码。

写博客效率好低(Orz)。。。

类型、对象、线程栈、托管堆运行时相互关系

下文讲到 对象类型对象 要注意区分

首先进程运行时,会在托管堆上创建一个System.Type的类型对象(文章后边解释)。然后线程创建时会分配一个1MB大小的栈。

先上一段代码(在书中代码基础上进行修改)

internal class Employee{
public Int32 GetYearsEmployed(){...} //非虚实例方法(实例方法)
public virtual String GenProgressReprot(){...}//虚实例方法(虚方法)
public static Employee LookUp(String name){...}//静态方法
}
internal sealed class Manager:Employee{
public override String GenProgressReport(){...}//重写方法(虚方法)
} void M1(){
String name="XiaoCong";
M2(name);
...
return
} void M2(String str){
Employee e;
Int32 year;
e = new Manager();
e = Employee.LookUp("ZhangSan");
year = e.GetYearsEmployed();
e.GenProgressReport();
}

1.首先执行M1方法,会在线程栈上创建1MB的栈空间,然后会加入 序幕 代码和 结尾 代码

序幕代码:进行一些初始化变量操作(初始化null或0)

结尾代码:压入【返回地址】

2.接着执行M2方法,将参数和返回地址,以及局部变量压入栈

3.CLR要确保程序集已经全部加载,然后创建M2内部引用对象的数据结构(类型对象)

  1. 数据结构包含类型对象指针、同步块索引、静态数据字段(包括基类中字段,字节数由对象自身中分配)、方法表。
  2. (String和Int32比较常用,可能实际编码过程中已经创建好了,就不在图中显示了。)
  3. Manager和Employee的 类型对象 指针指向Type。Type指向自身。
    类型对象本质也是对象,CLR创建这些对象时,必须初始化这些程序员。CLR在一个进程中运行时,就会立即创建一个特殊的System.Type类型的类型对象。
    Employee和Manager都是该类型的“实例”。因此他们的对象指针会指向Type。

4.然后M2方法会执行构造Manager对象

C# e = new Manager();

这会在托管堆中创建一个Manager类型对象的一个实例。即Manager 对象 (注意区分和类型对象的区别)。

该对象也包含类型对象指针和同步块索引。还包含必要的字节来容纳Manager类型定义的所有实例数据字段(包括基类字段)。

CLR会自动初始化内容类型对象指针,让它引用Manger类型对象。也会初始化同步块索引,并将对象的所有实例字段设为Null或0,然后调用类型构造器(修改实例字段数据)。

new 操作符返回Manager对象的内存地址,并将地址保存在变量e中。

5.M2下一步调用静态LookUp方法

C# e = Employee.LookUp("ZhangSan");

调用静态方法时,CLR会定位到静态方法的类型对象的类型对象(Employee类型对象)。然后找到对应的方法表中的记录项,对方法进行JIT编译(第一次执行该方法),再调用JIT生成的CPU指令。假设该方法到数据库中查找ZhangSan,然后返回一个全新的Manager对象,LookUp方法就会在堆上构造一个全新的Manager对象,用ZhangSan的数据库信息初始化它。然后返回该对象的地址保存在变量e中。然后旧的Manager对象会等待垃圾回收器进行回收释放。

6.M2下一步调用实例方法

C# year = e.GetYearsEmployed();

调用实例方法,JIT编译器会找到发出调用变量的类型(这里是e的类型Employee)的类型对象(Employee类型对象)。然后JIT查找记录项,对方法进行编译,执行CPU指令。

如果Employee类型没有定义那个方法,则会沿着基类一直寻找,直到Object类型。之所以能沿途查找,是因为每个类型对象都有一个字段引用了它的基类型。

假设该方法返回5,则year就会为5。

7.M2下一步调用虚方法(被Manager重写)

C# e.GenProgressReport();

调用虚方法,JIT要在方法中生成一些额外代码。这些代码首先检查发出调用的变量,然后跟随地址找到发出调用的对象(这里是新的Manager对象)。接着代码对象内部“类型对象指针”,然后在类型对象(Manager类型对象)方法表中查找记录项,编译成成CPU代码。

如果LookUp方法发现的是一个Employee类型,这里执行的就是Employee类型的GenProgressReport方法。

8.执行完M2方法之后,会找到返回地址,返回M1方法中继续执行

9.M1执行完成之后,会返回调用M1的方法继续执行

文章来源:http://xcong.cnblogs.com

.Net 类型、对象、线程栈、托管堆运行时的相互关系的更多相关文章

  1. 【.Net基础一】 类型、对象、线程栈、托管堆运行时的相互关系

    目前在看CLR via C#,把总结的记下来,索性就把他写成一个系列吧. 1.[.Net基础一] 类型.对象.线程栈.托管堆运行时的相互关系 2.[.Net基础二]浅谈引用类型.值类型和装箱.拆箱 J ...

  2. [CLR via C#]4. 类型基础及类型、对象、栈和堆运行时的相互联系

    原文:[CLR via C#]4. 类型基础及类型.对象.栈和堆运行时的相互联系 CLR要求所有类型最终都要从System.Object派生.也就是所,下面的两个定义是完全相同的, //隐式派生自Sy ...

  3. C# (类型、对象、线程栈和托管堆)在运行时的相互关系

    在介绍运行时的关系之前,先从一些计算机基础只是入手,如下图: 该图展示了已加载CLR的一个windows进程,该进程可能有多个线程,线程创建时会分配到1MB的栈空间.栈空间用于向方法传递实参,方法定义 ...

  4. C# 获取变量或对象的栈与堆地址

    C# 获取变量或对象的栈与堆地址 来源 https://www.cnblogs.com/xiaoyaodijun/p/6605070.html using System; using System.C ...

  5. (59)Wangdao.com第十天_JavaScript 对象在 栈和堆

    对象的属性值 如果要使用特殊的属性名,需 对象["属性名"] = 属性值       // 存 对象["属性名"]       // 取 obj["1 ...

  6. java中栈、堆和方法区的关系

    另外,常量池在方法区中

  7. C# 类型、对象、线程栈和托管堆在运行时的关系

    我们将讨论类型.对象.线程栈和托管堆在运行时的相互关系,假定有以下两个类定义: internal class Employee    {        public int GetYearsEmplo ...

  8. C# 运行时的关系

    简介 记录c#对象在托管堆中运行时的相互关系,如下记录了一个方法在执行时候的生命周期,当方法在之前,CLR会先执行将方法里面所有用到的局部变量.参数对应的内存地址等全部存放当前线程栈当中,并且会将所有 ...

  9. 【转】Java运行时数据区简介及堆与栈的区别

    理解JVM运行时的数据区是Java编程中的进阶部分.我们在开发中都遇到过一个很头疼的问题就是OutOfMemoryError(内存溢出错误),但是如果我们了解JVM的内部实现和其运行时的数据区的工作机 ...

随机推荐

  1. Java基础笔记-抽象,继承,多态

    抽象类: abstract修饰 抽象方法必须定义在抽象类中,抽象类不能创建对象. 在抽象方法中可以不定义抽象方法,作用是:让该类不能建立对象. 特点是: 1.定义在抽象类中 2.方法和类都用abstr ...

  2. PLSQL笔记

    /*procedurallanguage/sql*/--1.过程.函数.触发器是pl/sql编写的--2.过程.函数.触发器是在oracle中的--3.pl/sql是非常强大的数据库过程语言--4.过 ...

  3. Linux 07 故障恢复

    1. 模拟MBR扇区被破坏后的修复. MBR故障恢复: 1.备份 添加硬盘 启动操作系统: 添加硬盘: 对分区格式化: 挂载: 做备份: 破坏MBR 重启系统: 关闭虚拟机 设置光盘启动 救援模式: ...

  4. 详解VB.net编写DLL(动态链接库、应用程序扩展)文件

    首先,我们启动VS(Visual-Studio简称),我使用的是VS2008版本. 新建一个项目-选择内裤(额...不好意思)→类库 ,名称就默认吧. 编写类库没有窗体设计,因此我们不能使用工具箱中的 ...

  5. poj1160

    题目大意:在一个一维坐标轴上有v个(1<=v<=300)村庄,要建p(1<=p<=30)个邮局,每个村庄都到最近的邮局,要求最小的距离和.   四边形不等式,据说黑书上写得很高 ...

  6. NTFS 文件系统解析

    1. windows 下磁盘文件读写 下面是读取D:\磁盘上的第0扇区 512 Bytes CreateFile()打开磁盘,获取文件句柄: SetFilePointer()设置读写的位置: Read ...

  7. 关于html标签元素的data-*属性

    关于这个主题的文章和博客其实已经非常多了,这里并非要重复造轮子,只是看到一些例子稍微有点麻烦,其实也很简单,但是对于一个刚刚入门的人,w3c的例子甚至可能看不懂,这里列出一个最简单不过的小案例以供参考 ...

  8. [php]php时间戳当中关于时区的问题

    PHP_VERSION = 5.5.11 话说php函数 time() 的起始时间戳是从:GMT 1970-01-01 00:00:00 开始算起的 写了点测试代码: $gmt1 = strtotim ...

  9. HTML中的uniqueID

    Web页面上元素的name属性本身是可以重复的,理论上讲id是不可以重复的,但是现在的浏览器对重复的id都是默许的,可能有时候页面是需要一个唯一编号的.IE浏览器为页面上的所有元素都是提供了一个唯一名 ...

  10. 64位windows8的 IIS运行32位COM组件报错的解决

    浏览时报错如下: Microsoft VBScript 运行时错误 错误 '800a01ad'ActiveX 部件不能创建对象: 'sqlcomp.FileSystemObject'/config.a ...