老郑的博客

木叶飞舞之处,火亦生生不息!

C# 运行时的关系

简介

记录c#对象在托管堆中运行时的相互关系,如下记录了一个方法在执行时候的生命周期,当方法在之前,CLR会先执行将方法里面所有用到的局部变量、参数对应的内存地址等全部存放当前线程栈当中,并且会将所有实例字段设为null或者0,new操作之后才会返回对象的内存地址,。

 

线程栈

 1.CRL在运行的时候会启动一个进程,该进程包含多个线程,线程在进行创建的时候会分配到1MB的栈,栈空间用于向方法传递实参,方法内部定义的局部变量也在栈上。

 

 

 2.最简单的方法包含初始化代码,在方法开始工作前进行初始化,还包含结束代码,在方法工作后对其进行清理,下图展示了M1方法开始执行的时候,它的初始化代码在线程栈上分配局部变量name的内存,并且会在堆中为name开辟一块内存用来存储name

 

3.然后执行M2方法,将局部变量name作为实参传递,这里传递的其实是一个引用的地址也就是name变量所在内存中的位置,并且也会将返回地址也存到栈中,被调用的方法在结束之后,应该返回的位置,如下图所示:

 

 

4.当方法M2开始执行时,他的初始化代码在线程栈中为局部变量len和count分配内存,当M2方法内部代码执行完成之后,M2开始执行Return语句,造成CPU的指令指针被设置成栈中的返回地址,最终M1也会返回到它的调用者:

 

类存储

 假如现在存在一个类的定义,name现在基于这个类来进行讨论:

public class User{
 int age=18;
 string name="zyz";
 public  string getUserName(){...}

}

当window已经启动,CLR以加载到其中,并且托管堆也已初始化,c#编译器会把C#代码编译成IL(中间语言)并且由CLR当中的JIT把IL代码转换成本机cpu指令, JIT在编译的时候会生成。

在执行的时候M3内部引用的所有类型会注意到包括user,int,string类型,这时CLR要确定定义了这些类型的所有程序及都已经加载,然后利用程序集提取与这些类型相关的信息,创建一些数据结构来表示类型本身。如下图所示:

 

 

 

 

当CLR确认方法当中所有类型都已经创建,M3代码编译之后就允许线程执行M3的代码,M3的构造函数执行时必须在线程栈中为局部变量分配内存,  

 

 

当实例化User的时候,将会在托管堆中创建user类型的一个实例,并且该实例也有类型对象指针和同步块索引,该对象还包含了必要的字节来容纳user类型定义的所有数据字段(age,name),以及容纳由user的任何积累(本例只有Object,所有对象都继承system.object)定义的所有字段,任何时候在堆上新建对象,CLR都自动初始化内部的类型对象指针成员来引用和对象对应的类型对象。

 

 

当调用M3方法当中进行调用getUserName的时候,会对方法进行JIT编译,在调用JIT编译好的代码。

 

 

 

如有理解有误的地方,还请给与指正!~

posted @ 2019-08-11 12:31  zyz1  阅读(352)  评论(0编辑  收藏  举报