类型,对象,线程栈和托管堆在运行时的关系

两个类的定义:

public class Employee
{
  public Int32 GetYearsEmployed()
  {
    return 5;
  }

  public virtual String GenProgressReport()
  {
    return "";
  }

  public static Employee Lookup(String name)
  {
    return new Manager();
  }
}

public class Manager : Employee
{
  public override string GenProgressReport()
  {
    return base.GenProgressReport();
  }
}

调用方法:

void M3()
{
  Employee e;
  Int32 year;
  e
= new Manager();
  e
= Employee.Lookup("Joe");
  year
= e.GetYearsEmployed();
  e.GenProgressReport();
}

1.Windows进程启动,并加载CLR到该进程中。托管堆已初始化,并创建一个线程。

2.JIT编译器将M3转换成本地CPU指令,M3内部所引用的所有类型:Employee,Manager,Int32,String(因为“Joe”)都已经创建。假设M3之前已经执行过一些代码,不妨假定  Int32和String类型对象都已经创建,因为这些类型对象实在是太常用了。

   类型对象在堆上包括:a.类型对象指针                             

                                b.同步块索引

                                c.静态字段

                                d.方法表

3.CLR确定所有的类型对象都已创建之后,就允许线程开始执行M3的本地代码。在线程栈中为局部变量分配内存,并初始化所有的局部变量。e为null,year为0

4.M3代码中的 e = new Manager

   1).在托管堆中创建Manager类型的一个实例(Manager对象):

      a.类型对象指针

      b.同步块索引

      c.实例字段:

          Manager类型定义的所有实例字段

          Manager所有基类定义的所有实例字段

   2).初始化内部类型对象指针,使它引用与对象对应的类型对象(本例就是Manager类型对象)

   3).初始化同步块索引,并将所有实例字段设置为null或0,再调用类型的构造器

   4).new 操作符会返回Manager对象的内存地址,该地址保存在变量e中(e在线程栈上)

  

5. M3代码中的e = Employee.Lookup("Joe")

    调用一个静态方法,CLR会定位与定义静态方法的类型对应的类型对象,本例是Employee。然后在类型对象中查找与被调用方法对应的记录项,对该方法进行JIT编译,在调用JIT编译的代码。本例中Lookup方法内部返回的一个Manager对象,所以在堆上构建一个新的Manager对象,用Joe的信息初始化它,然后返回该对象的地址,这个地址保存到局部变量e中。此时,e不再引用第一个Manager对象,由于没有变量引用这个对象,所以垃圾回收机制会自动挥手这个对象占用的内存。

  

6.调用M3的 year = e.GetYearsEmployed()

   调用一个非虚实例方法,JIT编译器会找到与“发出调用的那个变量(e)的类型(Employee)”对应的类型对象(Employee类型对象),如果Employee中没有该方法,就会一直回溯类型层次结构到Object,并在沿途每个类型中查找该方法。找到该方法后,进行JIT编译,再调用JIT编译的代码。假定Employee的GetYearsEmployed返回5,这个整数就保存在局部变量year中,year也在线程栈上。

7.调用M3的e.GenProgressReport()

   检查发出掉哦用的变量,然后跟随地址来到发出调用的对象。在本例中,变量e引用的是代表“Joe”的一个Manager对象。然后,检查对象内部的“类型对象指针”成员,这个成员只想对象的实际类型。最后,在类型对象方法表中查找引用被带哦用方法的记录项,对方法进行JIT编译,再调用JIT编译过的代码。本例中会调用Manager的GenProgressReport。

   注意,如果Employee的Lookup发现是一个Employee对象而不是Manager对象,最终执行的是Emploee的GenProgressReport。

最后注意,Employee和Manager类型对象都包含“类型对象指针”成员。这是因为类型对象本质上也是对象。CLR创建类型对象时,必须初始化这些成员。CLR开始在一个进程中运行的时候,会立即为MSCorLib.dll中定义的System.Type类型创建一个特殊的类型对象。Employee和Manager类型对象都是该类型的“实例”。因此它们的类型对象指针成员会初始化为System.Type类型对象的引用。

注:本文内容出自《CLR Via C#》,如有什么不妥,请即时联系本人。

posted on 2011-07-12 23:38  Scarface  阅读(501)  评论(2编辑  收藏  举报

导航