• 类型,对象,线程栈和托管堆在运行时的相互关系(二)。


         类型,对象,线程栈和托管堆在运行时的相互关系(一)中说到类型,对象,线程栈和托管堆在运行时的相互关系。下面围绕CLR再来讨论这个问题。定义如下两个类。

    internal class Employee {
    public public Int32 GetYearsEmployed() { ... }
    public virtual String GenProgressReport() { ... }
    public static Employee Lookup(String name) { ... }
    }
    internal sealed class Manager : Employee {
    public override String GenProgressReport() { ... } public override String GenProgressReport() { ... }
    }

    现在假如Windows进程已经启动,CLR已经加载到了进程中,如在钱一章所讲,托管堆已经初始化,而起创建了一个线程(连同1M的线程栈)。该线程已经执行了一些代码,马上就要执行函数M3了,现在的线程栈,托管堆和M3函数体如下图:

                    

    当JIT(即时编译器)将M3的IL代码转换成本地的CPU指令时,会注意到M3内部引用的所有类型:Employee,Int32,Manager,String。这个时候CLR要确保定义了这些类型的所有程序集都已经加载到堆中。然后,利用程序集的元数据,CLR提取这些类的信息,并创建一些数据结构来表示类型本身。下图展示Manager和Employee类型对象使用的数据结构。因为这个线程在调用M3方法之前已经执行了一些代码,而且Int32和String是很常用的类型。所以假设Int32和String类型对象已经创建。

    (堆上的每个对象都有两个额外的成员:类型对象指针和同步块索引)。所以这两个对象都有这两个成员。

          定义一个类型时,可以在类型的内部定义静态数据字段。为这写静态数据字段的地址是在类型对象自身分配的。在每个类型对象中,最后都包涵一个方法表。在方法表中每个方法都有一个对应的记录项。

          现在,当CLR确定的方法需要的所有类型对象都已创建,而且M3的代码经过编译之后,就允许线程开始执行M3的代码,M3对"序幕"代码执行时,在线程战中为局部变量分配内存,而且会自动将局部变量初始化为NULL或者0。此刻线程栈,托管堆的情况如下图所示。

    然后是本次的重点。

       M3执行它的代码构造一个Manager对象。这就在托管堆中创建Manager类型的实例。创建完这个Manager对象以后,线程栈和托管堆的情款如下图:Manager对象也包涵类型对象指针和同步块索引两个成员。该对象还包括必要的字节来容纳Manager类型定义的所有实例数据字段,以及由Manager的任何基类定义的所有实例字段。在堆上创建一个对象,CLR都会自动初始化内部类型对象指针成员,让他引用与类型对象。然后CLR初始化同步块索引,并将对象的所有实例字段初始化为NULL或者0。然后调用类型的构造函数。改变类型内部实例字段。new 操作符返回的Manager对象在堆中的地址。该地址保存在e中。

         

         下次说说调用对象方法。

    参考CLR VIA C#

  • 相关阅读:
    11.枚举类.md
    10. Lambda表达式.md
    9.内部类
    8.抽象类、接口和多态.md
    7.final关键字.md
    jQuery学习笔记(5)-事件与事件对象
    Log4Net学习笔记(1)-完整的例子
    SqlServer知识点-操作xml
    NHibernate常见错误汇总(0)-持续更新中
    jQuery学习笔记(4)-设置元素的属性和样式
  • 原文地址:https://www.cnblogs.com/fantiantian/p/2520673.html
Copyright © 2020-2023  润新知