【.Net基础一】 类型、对象、线程栈、托管堆运行时的相互关系
目前在看CLR via C#,把总结的记下来,索性就把他写成一个系列吧。
1.【.Net基础一】 类型、对象、线程栈、托管堆运行时的相互关系
2.【.Net基础二】浅谈引用类型、值类型和装箱、拆箱
JIT(just in time)编译器
接下来的会讲到方法的调用,这里先讲下JIT编译器。以CLR书中的代码为例(手打...)。
以Main方法为例:
static void Main(){
Console.WriteLine("Hello");
Console.WriteLine("XiaoCong");
}
首先CLR会检测到Main方法中引用了一个Console类型,然后CLR会为其分配一个内部结构。
内部结构中每个方法都对应一个记录项,记录项中都容纳一个地址,根据此地址可以找到方法的实现。
对结构进行初始化时,会把记录项指向JITCompiler函数。

当第二次执行wirteLine时,由于第一次已经进行了验证和编译,所以跳过JIT函数,直接执行内存块中的代码。
写博客效率好低(Orz)。。。
类型、对象、线程栈、托管堆运行时相互关系
下文讲到对象和类型对象要注意区分
首先进程运行时,会在托管堆上创建一个System.Type的类型对象(文章后边解释)。然后进程中的线程创建时会分配一个1MB大小的栈。

先上一段代码(在书中代码基础上进行修改)
internal class Employee{
public Int32 GetYearsEmployed(){...} //非虚实例方法(实例方法)
public virtual String GenProgressReprot(){...}//虚实例方法(虚方法)
public static Employee LookUp(String name){...}//静态方法
}
internal sealed class Manager:Employee{
public override String GenProgressReport(){...}//重写方法(虚方法)
}
void M1(){
String name="XiaoCong";
M2(name);
...
return
}
void M2(String str){
Employee e;
Int32 year;
e = new Manager();
e = Employee.LookUp("ZhangSan");
year = e.GetYearsEmployed();
e.GenProgressReport();
}
1.首先执行M1方法,会在线程栈上创建1MB的栈空间,然后会加入序幕代码和结尾代码
序幕代码:进行一些初始化变量操作(初始化null或0)
结尾代码:负责方法完成之后对其进行清理操作。
调用一个方法时,还会将【返回地址】压入栈,方法在执行结束之后要返回这个位置。

2.接着执行M2方法,将参数和返回地址,以及局部变量压入栈

3.CLR要确保程序集已经全部加载,然后利用程序集中的元数据信息,创建M2内部引用对象的数据结构来表示类型本身
- 数据结构包含类型对象指针、同步块索引、静态数据字段(包括基类中字段,字节数由对象自身中分配)、方法表。
- (String和Int32比较常用,可能实际编码过程中已经创建好了,就不在图中显示了。)
- Manager和Employee的类型对象指针指向Type。Type指向自身。
类型对象本质也是对象,CLR创建这些对象时,必须初始化这些成员。CLR在一个进程中运行时,就会立即创建一个特殊的System.Type类型的类型对象。
Employee和Manager都是该类型的“实例”。因此他们的对象指针会指向System.Type的类型对象。
因为System.Type的类型对象本身也是一个对象,内部也有类型对象指针,所以指针指向自身。
顺便说一句,一个对象的GetType方法调用的是基类System.Object的方法。该方法返回的是当前对象的类型对象的指针,所以能够知道对象的真实类型。

4.然后M2方法会执行构造Manager对象
e = new Manager();
这会在托管堆中创建一个Manager类型对象的一个实例。即Manager对象(注意区分和类型对象的区别)。
该对象也包含类型对象指针和同步块索引。还包含必要的字节来容纳Manager类型定义的所有实例数据字段(包括基类字段)。
CLR会自动初始化内容类型对象指针,让它引用Manger类型对象。也会初始化同步块索引,并将对象的所有实例字段设为Null或0,然后调用类型构造器(修改实例字段数据)。
new 操作符返回Manager对象的内存地址,并将地址保存在变量e中。

5.M2下一步调用静态LookUp方法
e = Employee.LookUp("ZhangSan");
调用静态方法时,CLR会定位到静态方法的类型对象的类型对象(Employee类型对象)。然后找到对应的方法表中的记录项,对方法进行JIT编译(第一次执行该方法),再调用JIT生成的CPU指令。假设该方法到数据库中查找ZhangSan,然后返回一个全新的Manager对象,LookUp方法就会在堆上构造一个全新的Manager对象,用ZhangSan的数据库信息初始化它。然后返回该对象的地址保存在变量e中。然后旧的Manager对象会等待垃圾回收器进行回收释放。

6.M2下一步调用实例方法
year = e.GetYearsEmployed();
调用实例方法,JIT编译器会找到发出调用变量的类型(这里是e的类型Employee)的类型对象(Employee类型对象)。然后JIT查找记录项,对方法进行编译,执行CPU指令。
如果Employee类型没有定义那个方法,则会沿着基类一直寻找,直到Object类型。之所以能沿途查找,是因为每个类型对象都有一个字段引用了它的基类型。
假设该方法返回5,则year就会为5。

7.M2下一步调用虚方法(被Manager重写)
e.GenProgressReport();
调用虚方法,JIT要在方法中生成一些额外代码。这些代码首先检查发出调用的变量,然后跟随地址找到发出调用的对象(这里是新的Manager对象)。接着代码对象内部“类型对象指针”,然后在类型对象(Manager类型对象)方法表中查找记录项,编译成成CPU代码。
如果LookUp方法发现的是一个Employee类型,这里执行的就是Employee类型的GenProgressReport方法。
8.执行完M2方法之后,会找到返回地址,返回M1方法中继续执行
9.M1执行完成之后,会返回调用M1的方法继续执行
基础太差,个人理解不知道是否有错误,有错误请指正,谢谢。
看书不易,写博客也不易,该睡了。。。( ╯□╰ )
转载请注明出处:http://www.cnblogs.com/xcong/p/4060781.html
【.Net基础一】 类型、对象、线程栈、托管堆运行时的相互关系的更多相关文章
- [CLR via C#]4. 类型基础及类型、对象、栈和堆运行时的相互联系
原文:[CLR via C#]4. 类型基础及类型.对象.栈和堆运行时的相互联系 CLR要求所有类型最终都要从System.Object派生.也就是所,下面的两个定义是完全相同的, //隐式派生自Sy ...
- .Net 类型、对象、线程栈、托管堆运行时的相互关系
JIT(just in time)编译器 接下来的会讲到方法的调用,这里先讲下JIT编译器.以CLR书中的代码为例(手打...).以Main方法为例: static void Main(){ Cons ...
- C# (类型、对象、线程栈和托管堆)在运行时的相互关系
在介绍运行时的关系之前,先从一些计算机基础只是入手,如下图: 该图展示了已加载CLR的一个windows进程,该进程可能有多个线程,线程创建时会分配到1MB的栈空间.栈空间用于向方法传递实参,方法定义 ...
- C# 获取变量或对象的栈与堆地址
C# 获取变量或对象的栈与堆地址 来源 https://www.cnblogs.com/xiaoyaodijun/p/6605070.html using System; using System.C ...
- (59)Wangdao.com第十天_JavaScript 对象在 栈和堆
对象的属性值 如果要使用特殊的属性名,需 对象["属性名"] = 属性值 // 存 对象["属性名"] // 取 obj["1 ...
- java中栈、堆和方法区的关系
另外,常量池在方法区中
- C# 类型、对象、线程栈和托管堆在运行时的关系
我们将讨论类型.对象.线程栈和托管堆在运行时的相互关系,假定有以下两个类定义: internal class Employee { public int GetYearsEmplo ...
- JAVA基础-栈与堆,static、final修饰符、内部类和Java内存分配
Java栈与堆 堆:顺序随意 栈:后进先出(Last-in/First-Out). Java的堆是一个运行时数据区,类的对象从中分配空间.这些对象通过new.newarray.anewarray和mu ...
- java 线程栈 & java.lang.StackOverflowError
网上搜索了一下,关于java的线程栈: JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K. JVM的内存,被划分了很多的区域: (来源:http://www.iteye.com/ ...
随机推荐
- GitHub Pages站点官方宣布开始使用HTTPS
导读 数百万人依靠GitHub Pages,将其作为他们的网站主机,除此之外,还有数百万人每天访问这些网站.为了更好地保护到GitHub Pages站点的通讯,也为了鼓励在因特网上更广泛地采用HTTP ...
- Android 切换主题 (二)
Android 切换主题 (二) 背景 我原来写过一篇文章关于 android 切换主题的文章 -- Android 切换主题以及换肤的实现 , 里面介绍了如何使用 setTheme() 来切换主题, ...
- hdu 1300(dp)
一个模式的dp. Pearls Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)T ...
- 使用 paramsPrepareParamsStack 拦截器栈后的运行流程
2. 使用 paramsPrepareParamsStack 拦截器栈后的运行流程 1). paramsPrepareParamsStack 和 defaultStack 一样都是拦截器栈. 而 st ...
- [VS2015].NET4.0环境下使用.NET2.0程序集,使用sqlite时报异常 出现“混合模式程序集异常”
在.net 4.0环境下使用sqlite时报异常 混合模式程序集是针对“v2.0.50727”版的运行时生成的,在没有配置其他信息的情况下,无法在 4.0 运行时中加载该程序集其调用的方法是从sqli ...
- 2017 Multi-University Training Contest - Team 1—HDU6035
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6035 题意:一棵树有n个点,每个点有自己的颜色,任意两个不同的点可以组成一条路径.也就是说一共有n(n ...
- cloud native
什么是原生云(cloud native)应用? 原生云cloud-native应用的定义是:首先,应用系统应该与底层物理基础设施解耦.说白了,应用程序应该与操作系统等基础设施分离,不应该依赖Linux ...
- Period---hdu1358(循环节 kmp)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1358 题意 :求给你个串,前i位子串由某个字符串重复k次得到,求所有的i和k(k>1); 例如: ...
- 自定义HTTP头时的注意事项(转)
原文:https://blog.gnuers.org/?p=462 HTTP头是可以包含英文字母([A-Za-z]).数字([0-9]).连接号(-)hyphens, 也可义是下划线(_).在使用ng ...
- linux下的KSM内存共享机制分析
2017-04-26 KSM是内核中的一种内存共享机制,在2.6.36版本的内核中开始引入,简单来说就是其会 合并某些相同的页面以减少页面冗余.在内核中有一个KSM守护进程 ksmd,它定期扫描用户向 ...