CLR 基础-运行时的相互关系

CLR 基础-运行时的相互关系
 
解释类型、对象、线程栈和托管堆在运行时的相互关系。本文内容都是来自《CLR via C#》,这里只是做整理和梳理知识。
 
1 所有类型都从System.Object派生
 
所有类型最终都从System.Object 派生,所以每个类型的每个对象都保证了一组最基本的方法。
 
system.object的公共方法
 
    1 Equals
    2 GetHashCode
    3 ToString
    4 GetType
 
system.object的受保护方法
    
    MemberwiseClone:这个非虚方法创建类型的新实例,并将新对象的实例字段与this 对象的实例字段完全一致。返回对新实例的引用。
    Finalize:在垃圾回收器判断对象应该作为垃圾被回收之后,在对象的内存被实际回收之前,会调用这个虚方法。
 
 
CLR要求所有对象都用new 操作符来创建,以下是new 操作符所做的事情。
  1.  计算类型及其所有基类型(一直到System.Object)中定义的所有实例字段需要的字节数。堆上每对象都需要一些额外的成员,包括“类型对象指针 Type object pointer”和“同步块索引 sync block index”。CLR利用这些成员管理对象。
  2. 从托管堆中分配类型要求的字节数,从而分配对象的内存,分配的所有字节都设为零。
  3. 初始化对象的“类型对象指针”和“同步块索引”成员。
  4. 调用类型的实例构造器,传递在new调用中指定的参数。
 
 
2 类型转换
 
CLR最终要的特性之一就是类型安全。运行时,CLR总是知道对象是什么类型。因为GetType方法不是虚方法,一个类型不可能重写GetType返回一个其他类型。
 
  • 一个对象转换为它的基类是可以隐式的转换,
  • 然而将对象转换为它的某个派生类时,C#要求开发人员只能显示转换。
 
 
3 is 和 as 操作符来转型
 
is 操作符:
  • is 检查对象是否兼容于指定类型,返回 Boolean 值 true 或 false。
  • 注意,is 操作符永远不跑出异常。
  • 如果对象引用 null,is 操作符总是返回 false,因为没有可检查其类型的对象。
 
 
as 操作符:
如下代码所示:CLR 核实 o 是否兼容于 Employee 类型。
  • 如果是,as 返回非null 引用。
  • 如果 o不兼容于 Employee 类型,as 返回 null。
  • 注意:as 操作符只校验一次对象类型,if 只检查 e 是否为null。
 
 
4 运行时的相互关系
 
解释类型、对象、线程栈、和托管堆在运行时的相互关系。此外,还将解释调用静态方法,实例方法和虚方法的区别。
 
如下图展示了已加载 CLR 的一个Windows 进程。该进程可能有多个线程。线程在创建时会得到1MB 的栈,方法的参数和方法内部的局部变量都在这个栈上。现在,假定线程执行的代码要掉调用 M1 方法。
 
 
最简单的方法包含“序幕”代码,在方法开始工作前对其进行初始化;还包含“尾声”代码,在方法做完工作的时候进行清理。M1方法的序幕代码,在线程栈上分配局部变量 name 的内存。
 
 
 
 
然后,M1 调用 M2 方法,将局部变量 name 作为实参传递。M2 方法内部使用参数变量 s 标识栈位置。调用方法时还会将“返回地址”压入栈。
 
 
M2 方法的序幕代码在线程栈中为局部变量 length 和 tally 分配内存。最终,M2 抵达它的return 语句,造成 CPU 的指令指针被设置成栈中的返回地址。M2 的栈帧unwind,恢复成tu 4-3 的样子。之后,M1 继续执行M2 调用之后的代码,M1 的栈帧将准确反映 M1 的状态。
 
 
 
现在,让我们围绕CLR 来调整一下讨论。假定有以下两个类型定义:
 
Windows 进程已经启动,CLR已加载到其中,托管堆已初始化,而且已创建一个线程。线程已执行了一些代码,马上就要调用M3 方法。如图4-6 展示目前状态。M3 方法包含的代码将演示 CLR 如何工作.
 
JIT编译器将M3 的IL代码转换成本机CPU 指令时,会注意到M3 内部引用的所有类型。这时CLR 要确认定义了这些类型的所有程序集都已经加载。然后利用这些元数据,CLR提取与这些类型有关的信息,创建一些数据结构表示类型本身。
图4-7 展示了为 Employee 和 Manager 类型对象使用的数据结构。 定义类型时,可在类型内部定义静态数据字段。为这些静态数据字段提供支援的字节在类型对象自身中分配。
当CLR 确认方法需要的所有类型对象都已创建,M3 的代码已经编译之后,就允许线程执行M3 的本机代码。M3 的序幕代码执行时必须在线程栈中为局部变量分配内存。
 
 

你可能感兴趣的:(CLR 基础-运行时的相互关系)