文档章节

C#类型、对象、线程栈、托管堆在CLR中的关系

蓝宇
 蓝宇
发布于 2017/04/09 14:54
字数 1363
阅读 974
收藏 0

行业解决方案、产品招募中!想赚钱就来传!>>>

假设一个已经加载CLR组件的一个windows进程。该进程可能有多个线程。线程创建时会开辟栈空间。栈用于向方法传递实参,方法内部定义的局部变量也在栈上。

下图展示了线程的栈内存。栈从高位内存地址到地位内存地址构建。图中线程已经执行了一些代码,栈顶已经有些数据了,现在假设执行的代码调用了F1方法。

 

1. 首先它在线程栈上分配局部变量name的内存.

2. 然后F1调用F2方法,将局部变量name作为实参传递。name的局部变量地址被压入栈。

3. 调用方法有时会将返回地址压入栈

4. 在线程栈位length和tally分配内存。

5. 最终,F2抵达return,造成CPU指令指针被设置成栈的返回地址。F2的栈帧展开----出栈,栈的状态恢复到1的情况。

6. 最终F1会返回它的调用者。它的返回地址应该在1的上面。

 

现在讨论下一个话题

 

假定有以下两个类的定义:

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(){...}        

}

 

注意:堆上所有对象都包含两个额外的成员:类型对象指针和同步块索引。

其中对象指针指向类别.

同步块当使用lock锁定对象时,对象的同步块被设置一个整数,这个整数就是同步块的数组索引。初始情况,同步块索引位负数,当lock结束时,同步块索引又重新被设置成负数。

上图线程已经执行了一些代码,马上就要调用F3方法。

1. 首先JT编译器将F3的IL代码换成CPU指令时,会注意到F3内部引用的所有类型是否全部加载,然后利用程序集的元数据,提取预支相关的信息,创建一些数据结构来表示类型本身。

2. 由于线程已经执行了一些代码。所以不妨认为Int32 和String类对象已经创建好了。

3. 由于Employee定义了三个方法,Manager只定义了一个方法,所以Manager的方法表中只有一个记录项。

4. 当CLR确定方法需要所有的类型对象都已经创建,F3的代码编译后就允许线程执行F3的代码,在代码执行时就会对线程栈中的局部变量进行内存分配,CLR会将局部变量初始为null或0.

5. F3构造一个Manager对象引用

6. 局部变量year

7. 执行new Mnager。在托管堆上创建Mnager类型的一个实例,也就是一个Manager对象,和所有对象一样Mnager对象也有类型对象指针和同步块索引,该对象还要包含必要的字节来容纳Manager类型定义的所有实例数据字段,以及任何基类的所有实例字段,任何时候在堆上新建对象,CLR都会自定初始化内部的类型对象指针来因用对象对应的类型对象。此外在调用类型的构造函数之前,CLR会初始化同步块索引,并将对象所有实例字段设为null或0.new 操作符返回Manager对象的内存地址,将地址保存到局部变量e中。

8. 下一行代码调用Employee的LookUp方法,在调用静态方法时,CLR会定位与定义静态方法的类型对应的类型对象,然后,JIT会在类型对象的方法表中查找与被调用方法对应的记录项,进行JIT编译(如果需要),然后调用编译好的代码,在调用此方法时,会在堆中构造一个新的Manager,e不再引用第一个Manager对象。

9. 下一行调用Employee的非虚实例方法GetYearsEmployee。调用非虚方法时,JIT会找到发出调用的哪个变量e的类型,这时e被定义成Employee,如果Employee没有此方法,JIT会一直回溯直到Object或找到那个方法。,之所以可以如此回溯,是因为每个类型对象都有一个字段引用了它的基类型。

10. F3的下一行调用Employee的虚方法GetProgressReport。调用虚实例方法时,JIT要在方法中生成一些额外的代码。方法每次调用都会执行这些代码,这些代码首先检查发出调用的变量,并跟随地址检查类型对象指针成员,该成员指向对象的实际类型,然后在实际类型的方法表中找到记录项。

 

注意:Employee和Manger类型对象都包含类型对象指针。这是因为类型对象本质上也是对象。CLR创建类型时,必须先初始化这些变量。CLR在运行时,会理解为MSCorLib.dll 中定义的System.Type类型创建一个特殊的类型对象。上述两个类型对象都是它的实例。所以它们的类型对象指针是System.Type类型对象的引用,而System.Type类型对象的类型对象指针是它自己。

 

蓝宇
粉丝 1
博文 7
码字总数 5793
作品 0
呼和浩特
私信 提问
加载中
请先登录后再评论。
Swift百万线程攻破单例(Singleton)模式

一、不安全的单例实现 在上一篇文章我们给出了单例的设计模式,直接给出了线程安全的实现方法。单例的实现有多种方法,如下面: class SwiftSingleton { } 这段代码的实现,在shared中进行条...

一叶博客
2014/06/20
3.4K
16
beego API开发以及自动化文档

beego API开发以及自动化文档 beego1.3版本已经在上个星期发布了,但是还是有很多人不了解如何来进行开发,也是在一步一步的测试中开发,期间QQ群里面很多人都问我如何开发,我的业余时间实在...

astaxie
2014/06/25
2.7W
22
5分钟 maven3 快速入门指南

前提条件 你首先需要了解如何在电脑上安装软件。如果你不知道如何做到这一点,请询问你办公室,学校里的人,或花钱找人来解释这个给你。 不建议给Maven的服务邮箱来发邮件寻求支持。 安装Mav...

fanl1982
2014/01/23
1.2W
6
代码生成器--Codgen

Codgen是一个基于数据库元数据模型,使用freemarker模板引擎来构建输出的代码生成器。freemarker的数据模型结构通常来说都是一个Map树状结构模型,codgen也不例外,它的数据模型这棵树的根节...

黄天政
2013/01/29
1.4W
2
Web开发组件管理器--Bower

Bower 是一个针对Web开发的包管理器。该工具主要用来帮助用户轻松安装CSS、JavaScript、图像等相关包,并管理这些包之间的依赖。 功能有些类似于Component。不同之处是,Component是围绕Git...

匿名
2013/02/01
1.2W
2

没有更多内容

加载失败,请刷新页面

加载更多

数据库高频面试点,事务/乐观锁/悲观锁/CAS/MySQL存储引擎

事务的ACID特性是什么? 原子性: 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用; 一致性: 执行事务前后,数据保持一致,多个事务对同一个数据读...

osc_45536bvu
39分钟前
16
0
大数据BI软件助力企业数字化转型

当下,「新基建」势头正盛,随着“新基建”成为热议话题,数字化也随之成为企业面临的新机遇和新挑战。新基建的核心就是数据,数据是数字经济和企业数字化转型的生产要素和发展动力。 再看看...

osc_0boqdoe2
40分钟前
0
0
凯旋创投来志刚:基因治疗新时代,大戏刚刚开始

  2017 年,全球第一个基因治疗方法 CAR-T 细胞药物 Kymriah 获得 FDA 上市批准,从此掀起了基因治疗的热潮。随着相关技术和政策的不断成熟,基因治疗市场也随之扩大。根据德勤发布的《引领...

osc_k3vwonkw
41分钟前
10
0
LightningChart.NET使用两个BarSeries创建简单的2D图表

本教程介绍了如何使用两个BarSeries创建简单的2D图表。 BarSeries将数据值表示为矩形条,并且可以用于以非常清晰的方式可视化数据之间的差异和方差。 在本教程中,BarSeries用于表示两年期间...

roffey
42分钟前
0
0
Mybatis trim 标签的 2 个妙用!

云栖号资讯:【点击查看更多行业资讯】 在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! mybatis的trim标签一般用于去除sql语句中多余的and关键字,逗号,或者给sql语句前拼...

osc_x03qsedc
43分钟前
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部