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

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介:

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 界的经典之作,读的过程写点笔记跟大家分享,我也推荐大家看英文版,能够直接领会原意   

本文转自Rt-张雪飞博客园博客,原文链接http://www.cnblogs.com/mszhangxuefei/archive/2012/07/24/clrnotes-4.html如需转载请自行联系原作者


张雪飞

相关文章
|
2月前
|
编解码 网络协议 API
Netty运行原理问题之Netty的主次Reactor多线程模型工作的问题如何解决
Netty运行原理问题之Netty的主次Reactor多线程模型工作的问题如何解决
|
5天前
|
移动开发 Android开发 数据安全/隐私保护
移动应用与系统的技术演进:从开发到操作系统的全景解析随着智能手机和平板电脑的普及,移动应用(App)已成为人们日常生活中不可或缺的一部分。无论是社交、娱乐、购物还是办公,移动应用都扮演着重要的角色。而支撑这些应用运行的,正是功能强大且复杂的移动操作系统。本文将深入探讨移动应用的开发过程及其背后的操作系统机制,揭示这一领域的技术演进。
本文旨在提供关于移动应用与系统技术的全面概述,涵盖移动应用的开发生命周期、主要移动操作系统的特点以及它们之间的竞争关系。我们将探讨如何高效地开发移动应用,并分析iOS和Android两大主流操作系统的技术优势与局限。同时,本文还将讨论跨平台解决方案的兴起及其对移动开发领域的影响。通过这篇技术性文章,读者将获得对移动应用开发及操作系统深层理解的钥匙。
|
1月前
|
Java Spring
运行@Async注解的方法的线程池
自定义@Async注解线程池
56 3
|
2月前
|
存储 数据挖掘 大数据
深度解析Hologres计算资源配置:如何根据业务场景选择合适的计算类型?
【8月更文挑战第22天】Hologres是一款由阿里云提供的分布式分析型数据库,支持高效的大数据处理与分析。本文通过电商优化商品推荐策略的案例,介绍了Hologres中的计算组型与通用型配置。计算组型提供弹性扩展资源,适合大规模数据及高并发查询;通用型则适用于多数数据分析场景,具备良好计算性能。通过实例创建、数据加载、计算任务建立及结果查询的步骤展示,读者可理解两种配置的差异并根据业务需求灵活选择。
39 2
|
2月前
|
消息中间件 设计模式 安全
多线程魔法:揭秘一个JVM中如何同时运行多个消费者
【8月更文挑战第22天】在Java虚拟机(JVM)中探索多消费者模式,此模式解耦生产与消费过程,提升系统性能。通过`ExecutorService`和`BlockingQueue`构建含2个生产者及4个消费者的系统,实现实时消息处理。多消费者模式虽增强处理能力,但也引入线程安全与资源竞争等挑战,需谨慎设计以确保高效稳定运行。
68 2
|
2月前
|
缓存 JavaScript 前端开发
|
2月前
|
存储 安全 程序员
|
2月前
|
前端开发 UED 开发者
React组件优化全攻略:深度解析让你的前端应用飞速运行的秘诀——从PureComponent到React.memo的彻底性能比较
【8月更文挑战第31天】在构建现代Web应用时,性能是提升用户体验的关键因素。React作为主流前端库,其组件优化尤为重要。本文深入探讨了React组件优化策略,包括使用`PureComponent`、`React.memo`及避免不必要的渲染等方法,帮助开发者显著提升应用性能。通过实践案例对比优化前后效果,不仅提高了页面渲染速度,还增强了用户体验。优化React组件是每个开发者必须关注的重点。
47 0
|
2月前
|
Kotlin
Kotlin 运算符详解:算术、赋值、比较与逻辑运算符全解析
## Kotlin 运算符 - **用途**: 对变量和值执行操作。 - **示例**: ```kotlin var x = 100 + 50 // 150 ``` - **分类**: - **算术**: `+`, `-`, `*`, `/`, `%`, `++`, `--`. - **赋值**: `=`, `+=`, `-=`. - **比较**: `==`, `!=`, `<`, `>`, `<=`, `>=`. - **逻辑**: `&&`, `||`, `!`.
26 2
|
2月前
|
算法 网络架构

热门文章

最新文章

推荐镜像

更多
下一篇
无影云桌面