new,is和as运算符解析及运行时类型,对象,线程堆栈,托管堆之间的联系

CLR要求对象必须使用new运算符创建,在使用new运算符创建一个对象时具体都做了些什么呢?

1.计算所有定义的实例字段,所有的基类型包括System.Object需要分配的字节数。

每一个堆上的对象还需要两个额外的成员:类型对象指针同步块索引,CLR使用它们来管理对象。它们两个需要的字节数算在对象的大小里面。

2.从托管堆分配对象需要的字节数(也就是给对象分配内存)。所有的字节置为0

3.初始化类型对象指针 同步块索引

4.调用实例构造器。大多数编译器自动生成调用基类构造器的代码。最终会调用Sytem.Object的构造器,这个构造器方法什么也不做,只是return。

在new执行完上面的操作以后,返回一个新创建的对象的引用,这个引用保存在实例对象变量里。如:A a=new A();   保存在变量a里。

 

is和as运算符

//o是一个Object对象    Employee是一个类
if(o is Employee)
{
     Employee e=(Employee)o;
     ...
}

上面的代码是关于is非常典型的应用,这里CLR会进行两次类型 检查:①is运算符检查   ②执行强转的时候检查。CLR的类型检查提高了安全性,同时也会消耗一部分性能。C#提供了as运算符来简化代码并且改善性能。

Employee  e=o as Employee;
if(e!=null)
{
    //...
}

这里CLR会检查o的类型是否兼容Employee,如果兼容则返回Employee对象的引用,否则返回null。这里只执行了一次类型检查

 

运行时类型,对象,线程堆栈,托管堆之间的联系

当创建一个线程时,会分配1M的堆栈空间,用来向方法传递参数以及存放定义在方法里面的局部变量。堆栈的建造是从高位内存地址向地位内存地址进行。下面演示一个线程执行调用M1方法的过程:

M1方法执行时,首先会在堆栈上为name变量分配内存:

接着M1调用M2方法,将name局部变量作为参数参数传递,name变量的地址进栈:

接着会执行M2方法,首先还是给length和tally两个局部变量从堆栈上分配内存:

M2执行到return语句,返回到M1,继续执行。

 

调用静态方法,实例方法以及虚方法之间的不同

internal  class Employee
{
     public          Int32     GetYearsEmployed()     { ...  }
     public  virtual String     GetProgressReport()  { ...  }
     public  static   Employee   Lookup(String  name)  { ...  }
}  

internal  sealed  class Manager : Employee
{
     public  override  String     GetProgressReport()  { ...  }
}

加入代码接着调用M3方法,M3方法包含的代码阐释了CLR的运行原理(一般可能不这样写代码)

上图展示CLR载入到进程,托管堆初始化。

当JIT编译器将M3的IL代码编译为本地CPU指令时,CLR会保证定义这些类型的程序集加载。使用程序集的元数据,CLR这些类型的信息并创建一些数据结构来呈现类型本身。关于Employee和Manager类型展示如下:

(Int32和String是常用的类型,这里没有展示)

1.在定义一个类型时,可以定义一个静态数据字段,存放类型对象本身的内存分配的字节数。每一个类型对象里面是一个包含每个方法入口的方法表,这里的Employee定义了GetYearsEmployed , GetProgressReport, 和Lookup三个方法,所以在Employee的方法表里面有三个入口。在CLR确定了所有的方法被创建并编译之后,线程开始执行M3的CPU指令。同样,这里会为M3方法的局部变量分配内存,(初值为0或null)。

2.接着M3执行构造器创建Manager对象,

3.接着执行下面的代码,M3调用静态方法Lookup。当调用静态方法时,JIT编译器会定位到跟定义静态方法相对应的类型对象。然后,JIT编译器定位到方法表的入口处。Lookup方法在堆上构造了一个Manager对象并且返回该对象的地址。保存在变量e中,此时e不再指向开始new出来的那个Manager对象,开始的Manager对象已经没有变量引用它。在未来某个时候GC会对它进行回收。

4.接着M3调用非虚方法的实例方法GetYearsEmployed,CLR会定位到与变量e类型一致的对象。(如果Employee没有定义该方法,JIT编译器会向上一层层查找直到Object。)

然后JIT编译器定位到对象的方法表,这里可以看出相对于静态方法多了一步定位。编译该方法(如果之前没有编译过),调用编译后的代码。

5.接着M3调用虚方法实例方法GetProgressReport,调用时,JIT会生成一些额外的代码,这些代码在每一次方法调用时都会执行,它会首先会查找发起调用的变量,然后跟随地址来调用对象。这里的e变量执行了Manager对象,生成的额外的代码会检查对象内部的类型对象指针,该指针成员引用了实际的对象的类型。然后定位到对象的方法表,接着编译。

 

 

注   《CLR via C#》(Jeffrey Richter著)——.NET 界的经典之作,读的过程写点笔记跟大家分享,我也推荐大家看英文版,能够直接领会原意  

时间: 2024-09-15 10:47:31

new,is和as运算符解析及运行时类型,对象,线程堆栈,托管堆之间的联系的相关文章

编程-c++ 运算符的重载 运行时出现 debug 请各位大神帮忙找错

问题描述 c++ 运算符的重载 运行时出现 debug 请各位大神帮忙找错 // Chapter 8 of C++ How to Program// doubleScriptedArray.h#ifndef DARRAY_H#define DARRAY_H #include using std::ostream;using std::istream; class DoubleScriptedArray { friend ostream &operator<<(ostream&

如何在运行时确定对象类型(RTTI)

RTTI 是"Runtime Type Information"的缩写,意思是:运行时类型信息. 它提供了运行时确定对象类型的方法.本文将简略介绍 RTTI 的一些背景知识.描述 RTTI 的概念,并通过具体例子和代码介绍什么时候使用以及如何使用 RTTI:本文还将详细描述两 个重要的 RTTI 运算符的使用方法,它们是 typeid 和 dynamic_cast. 其实,RTTI 在C++中并不是什么新的东西,它早在十多年以前就已经出现了.但是大多数 开发人员,包括许多高层次的C++

举例讲解Java的RTTI运行时类型识别机制_java

1.RTTI:运行时类型信息可以让你在程序运行时发现和使用类型信息. 在Java中运行时识别对象和类的信息有两种方式:传统的RTTI,以及反射.下面就来说下RTTI. RTTI:在运行时,识别一个对象的类型.但是这个类型在编译时必须已知. 下面通过一个例子来看下RTTI的使用.这里涉及到了多态的概念:让代码只操作基类的引用,而实际上调用具体的子类的方法,通常会创建一个具体的对象(Circle,Square,或者Triangle,见下例),把它向上转型为Shape(忽略了对象的具体类型),并在后面

C++:RTTI(RunTime Type Information)运行时类型信息 详解

RTTI, RunTime Type Information, 运行时类型信息, 是多态的主要组成部分, 通过运行时(runtime)确定使用的类型, 执行不同的函数,复用(reuse)接口. dynamic_cast<>可以 使基类指针转换为派生类的指针, 通过判断指针的类型, 可以决定使用的函数. typeid(), 可以判断类型信息, 判断指针指向位置, 在多态中, 可以判断基类还是派生类. 代码: /* * test.cpp * * Created on: 2014.04.22 * A

Java进阶教程之运行时类型识别RTTI机制_java

运行时类型识别(RTTI, Run-Time Type Identification)是Java中非常有用的机制,在Java运行时,RTTI维护类的相关信息. 多态(polymorphism)是基于RTTI实现的.RTTI的功能主要是由Class类实现的. Class类 Class类是"类的类"(class of classes).如果说类是对象的抽象和集合的话,那么Class类就是对类的抽象和集合. 每一个Class类的对象代表一个其他的类.比如下面的程序中,Class类的对象c1代

基于Java 2运行时安全模型的线程协作

本文配套源码 在Java 2之前的版本,运行时的安全模型使用非常严格受限的沙箱模型(Sandbox).读者应该熟悉,Java 不受信的Applet代码就是基于这个严格受限的沙箱模型来提供运行时的安全检查.沙箱模型的本质是,任何本地运行的代码都是受信的,有完全的权限来存取关键的系统资源.而对于Applet,则属于不受信的代码,只能访问沙箱范围内有限的资源.当然,您可以通过数字签名的方式配置您的Applet为受信的代码,具有同本地代码一样的权限. 从Java 2开始,Java 提供了基于策略(Pol

TypeLoadException: 找不到 Windows 运行时类型“Windows.UI.Xaml.Controls.Binding

奇怪的问题,我以为是我不小心添加了什么标签导致的,后来发现...坑爹,把项目名字改一下,然后移除掉,接着再加载一下就可以了.......崩溃了,,,,事实证明==>这个时候再把名字改回去也是不报错的..!!!!我没动代码啊! 还有一种,说未识别代码什么的错误,如果不是人为因素也可以这样解决

网页运行时提示对象不支持abigimage属性或方法_javascript技巧

在一个网页中用了一个js插件, js文件引用的没有错,代码也和demo差不多, 但是运行时ie的调试工具报了一个错: 解决方案: jquery文件冲突,发现原来自己引过一个 <script src="js/jquery-1.11.0.min.js"></script> , 这里又引入了一个 <script type="text/javascript" src="js/jquery-2.0.3.min.js">&

iOS学习之Objective-C 2.0 运行时系统编程

0 导言 本主主要内容包括: 1.概述 2.参考 3.运行时系统的版本和平台 4.和运行时系统的交互 5.消息 6.动态方法解析 7.消息转发 8.类型编码 9.属性声明 1 概述 Objective-C语言将决定尽可能的从编译和链接时推迟到运行时.只要有可能,Objective-C总是使用动态的方式来解决问题.这意味着Objective-C语言不仅需要一个编译器,同时也需要一个运行时系统来执行编译好的代码.这里的运行时系统扮演的角色类似于 Objective-C语言的操作系统,Objectiv