CLR via C# -----类型基础

4.1

引用类型的开销:实例字段、类型对象指针、同步块索引

new操作符创建对象

1.它计算类型以及所有基类型(一直到System.Object,虽然它没有定义自己的实例字段)中定义的所有实例字段需要的字节数。堆上的每个对象都需要一些额外的成员---即“类型对象指针”和“同步块索引”。 这些成员由CLR用于管理对象。这些额外成员的字节数会计入对象大小。

2.它从托管堆中分配制定类型要求的字节数,从而分配对象的内存,分配的所有字节都设为0.

3.它初始化对象的“类型对象指针”和“同步块索引”成员。

4.调用类型的实力构造器,向其传入在对new的调用中指定的任何实参。大多数编译器都在构造器重自动生成代码来调用一个基类构造。每个类型的构造在调用时,都要负责初始化由这个类型定义的实例字段。最终调用的说System.Object的构造器,由下向上依次调用构造器。


4.2 类型转换

GetType()是非虚方法,不能被重写将一个类型伪装成另一个类型。

CLR运行时,而已将对象转换为对象的实际类型和它的任何基类。

使用is和as操作符转型

Employee e = o as Employee;

if (e!=null){

}

internal class B{} //基类

internal class D : B{} //派生类


4.4 运行时的互相联系

进程可能存在多个线程。一个线程创建时,会分配到一个1MB大小的栈。这个栈的空间用于向方法传递实参,并用于方法内部定义的局部变量。

栈帧代表当前线程的调用栈中的一个方法调用。在执行线程的过程中进行的每个方法调用都会在调用栈中创建并压入一个StackFrame。

void M3(){

Emloyee e;

Int32 year;

e = new Manager();

e = Emloyee.Lookup("Joe");

year = e.GetYearsEmployed();

e.GenProgressReport();

}

堆上新建对象时,CLR先初始化内部类型对象指针成员,让它引用与对象对应的类型对象,此外,CLR会先初始化同步块索引,并将对象的所有实例对象字段设为null或0,再调用类型的构造器(从派生到基类),new操作符会返回对象的内存地址,到线程栈上。


如果Employee类型没有定义正在调用的那个方法,JIT编译器会回溯(直到Object),并在沿途的每个类型中查找该方法,之所以能这样回溯,是因为每个类型对象都有一个字段引用了他的基类型。

类型对象指针指向对象的实际类型对象(类型对象包含静态字段和方法表),根据实际类型的方法表,查找引用了被调用方法的记录项,对方法进行了JIT编译,再调用JIT编译过的代码。

类型对象指针是System.Type类型对象(Employee类型对象是该类型的“实例”)的引用。System.Object的GetType方法返回的是存储在指定对象的“类型对象指针”成员中的地址。


你可能感兴趣的:(CLR,via,C#)