时间:2021-05-20
本文不再对值类型进行讨论,主要讨论一下引用类型。如要看内存值类型的朋友可以看一下前一篇C#之CLR内存原理初探。
C#引用类型具体分析如下:
先来装备两个类:
internal class Employee{ public static Employee LookUp(string name) { return null; } public virtual string GetProgressReport() { return string.Empty; }}internal class Manager : Employee{ public override string GetProgressReport() { return string.Empty; }}Employee类里有一个虚方法GetProgressReport和一个静态方法LookUp,Manager类继承了Employee并重写了GetProgressReport.
static void Main(string[] args){ Employee e = new Manager(); e = e.LookUp("Tom"); e.GetProgressReport();}我们在Main里面写上这样的代码,再来对照着下图看看栈和堆是怎么运作的。
当JIT编译器将这些IL代码转换成本地CPU指令时,会注意到所有的类型:Employee,Manager,String(由于Tom字符串).
1.当运行方法之前,"prologue"代码会为这些对象在内存中开辟空间。
2.Employee e=new Manager();会把e压入栈,然后保存Manager对象地址,我们在初级篇的时候说过,每个对象都有一个同步块索引和类型对象指针,这个指针就是内存的地址。
3.e=Employee.LookUp("Tom");调用一个静态方法时,CLR会定位与定义静态方法的类型对应的类型对象。然后JIT编译器在类型对象的方法表中查找与被调用的方法对应的记录项,对方法进行JIT编译(如果需要的话),再调用JIT编译的代码。这个时候我们知道LoopUp返回的是Employee对象(这时,我们一开始创建的Manager对象还不确认有没有被清除,因为GC会自动去清理这些托管代码),所以在堆上面开辟一个Employee的内存块并把e的地址改变成Employee对象所在的位置。
注意:Employee和Manager类型对象都包含了“类型指针对象”成员。这时由于类型对象本质上也是对象。CLR创建类型对象时,必须初始化这些成员。初始化成什么呢?CLR开始在一个进程中运行时,会立即为MSCorLib.dll中定义的System.Type类型创建一个特殊的类型对象。Employee和Manager类型对象都是该类型的”实例“。 因此,它们的类型对象指针成员会初始化成对System.Type类型对象的引用。
顺便说一句Object.GetType返回的就说”类型指针对象“所存储的地址。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
本文初步讲述了C#的CLR内存原理。这里所关注的内存里面说没有寄存器的,所以我们关注的只有托管堆(heap),栈(stack),字符串常量池(其中string是
本文实例讲述了C#实现终止正在执行的线程的实现方法,并针对一些容易出错的地方进行了深入分析,具体方法如下:一般来说,很多人都会使用Abort方法来终止线程,其实
本文通过一个C程序实例对C语言中自动隐式转换与类型强制转换的注意点进行深入分析,详情如下:先看一个C程序:#include#include#includedou
CLR支持两种类型:引用类型和值类型。引用类型总是从托管堆上分配的。c#中的New操作符返回对象的内存地址。引用对象的注意点:1、内存从托管堆中分配2、堆上分配
命名空间是C++非常重要的概念,本文就以实例形式对其进行深入分析,具体内容如下:通常来说,在C++中,命名空间(namespace)的目的是为了防止名字冲突。每