C#运行时的相互关系
C#运行时的相互关系
本博客主要讲述运行时类型、对象、线程栈和托管堆之间的相互关系,静态方法、实例方法和虚方法的区别,以及内存的分配和回收。
线程栈:在一个进程中可能包含多个线程,一个线程在创建的时候,会分配到一个大小1MB大小的栈,栈用于存储方法的实参、形参以及方法内部的局部变量,栈是从高位内存地址向地位地址构建的,由于栈有先进后出的特点,所以先定义的变量后被回收。
下面来看一个简单的例子,让你更了解线程栈
由于线程栈是从高位开始分配内存,先分配的我就画在上面了,在调用F1();方法时,分配内存的顺序是:name->n->F2的返回地址->Age->name;回收内存的顺序当然是反过来的。在一个方法中,应该包含一些序幕代码,进行一些初始化工作,还有一些尾声代码,等方法执行完成之后做一些回收工作。由于方法的返回地址先分配,在方法执行完成的时候回到返回地址,递归太深就容易出现栈溢出,请看我的《递归再一次让哥震惊了》,因为参数、局部变量都必须等到方法返回的时候才能回收。
在介绍托管堆之前先看看两个简单的类:
public class Person {private int height;public void SetHeight(int height) {this.height = height; }public virtual void Say(string word) { }public static string Head() {return "my head"; }public static int Age = 100; }public class Student : Person {public override void Say(string word) { Console.WriteLine(word); } }
static void Main(string[] args) { Person student = new Student(); student.Say("Hello cth"); student.SetHeight(172); Person.Head(); Console.ReadLine(); }
CLR会在第一次访问一个对象时加载该对象,在这里,定义变量student时会为Person对象在线程栈中分配内存,第一次加载吗,在构造一个Student对象之前先要加载Student对象,并为Student类型对象分配内存,并构建一个Student对象。对象的地址存入线程栈中的局部变量student 中,我们知道类型对象的内容包含:类型对象指针、同步索引块、静态字段和方法(静态的和非静态的),不管是类型对象、还是实例类型都必须有类型对象指针、同步索引块;我们知道静态字段属于类,被这个类的所有实例共享,当然静态字段的内存是在类型本身中分配的,方法也是类的所有实例共享的,他的内存也是在类型本身中分配的,在每一个类型对象中都有一个方法表,类中定义的方法都有一个对应的项。
在构造一个对象的实例时,只需要为类型对象指针、同步索引块、该对象的实例字段分配内存,对于对象实例来说,类型对象指针可以让实例访问类型对象中德静态字段、方法等。
Student是线程栈中的定义的一个局部变量,保存Student的一个实例的在托管堆中的地址,所以他可以访问Student对象中的字段,方法,其实访问方法是通过类型对象指针访问类型对象Student中的方法表中对象的项。
Say方法的执行过程:变量student指向的是一个Student对象,调用的当然是Student类型对象中的Say方法,尽管在定义student的时候是Person类型,因为他是引用类型,他指向的是托管堆中Student对象的内存,然后遍历该对象的方法表,找到该方法调用。
特别说明虚方法,JIT在虚方法中加了一些额外的代码,方法每次调用的时候都会执行这些代码,这些代码会检查发出调用的变量,然后根据这个变量找到其应用的对象,然后调用这个对象的方法,若没有这些代码,你觉得CLR是调用父类的方法还是调用之类的方法呢,虚方法带来方便的同时,也多了这些必须的检查的代码。
SetHeight方法的执行过程:和Say方法前面是一样,只是在遍历Student对象的方法表时没有找到该方法,我们知道父类中定义的非private方法都可以被子类继承,是因为每个类型都定义了一个字段引用了他的基类,如果一个类调用的方法那个方法不是自己定义的,那么编译器会回溯类层次结构,一直到基类Object,找到相关的方法并调用,如果没有找到相关的方法就报了异常呗。所以SetHeight方法其实调用的是Person中的SetHeight方法。
Head方法的执行:由于Head方法是静态方法和上面两个方法有所不同,调用静态方法的时候,CLR会定位与静态方法对象的类型对象,然后在对应实例对象对象的方法表中查找相关的记录项,如果没有找到,同样会回溯。
当执行完student.SetHeight(172);时,student在也没有被引用,成为垃圾,在其所在的方法返回之前将会被回收,也就是说student实例对象被回收,释放其所在的内存,而类型对象不会被回收,类型对象的生成周期是:对象被加载到CLR中,直到其所在的AppDomain卸载。静态字段是他所引用类型的跟,所以被静态类型引用的对象永远不会被回收,如果其引用的是一个集合对象,并向其中不断的加入元素的话,就会造成内存泄露,更多关于内存管理垃圾回收,请看我的另一篇博客《垃圾回收--代》
作者:陈太汉
博客:http://www.cnblogs.com/hlxs/
C#运行时的相互关系相关推荐
- C# (类型、对象、线程栈和托管堆)在运行时的相互关系
在介绍运行时的关系之前,先从一些计算机基础只是入手,如下图: 该图展示了已加载CLR的一个windows进程,该进程可能有多个线程,线程创建时会分配到1MB的栈空间.栈空间用于向方法传递实参,方法定义 ...
- .Net运行时的相互关系
阅读目录 前言 线程堆栈的分配 托管堆上对象的分配 结束语 前言 .Net中的运行时,以及各个类型.对象.线程堆栈以及托管堆之间的关系,在初学者(俺是初学者中的菜鸟 J)看来,有很多是难以理解的东西, ...
- 类型,对象,线程栈和托管堆在运行时的相互关系(一)。
当系统加载一个CLR的进程,进程里面可能有多个线程,这时候系统会给这个进程创建一个大小为1M的线程栈.这个线程栈用来存放方法调用的实参,和方法内部定义的局部变量.下图展示了一个线程栈的栈内存.线程栈的 ...
- [CLR via C#]4. 类型基础及类型、对象、栈和堆运行时的相互联系
原文:[CLR via C#]4. 类型基础及类型.对象.栈和堆运行时的相互联系 CLR要求所有类型最终都要从System.Object派生.也就是所,下面的两个定义是完全相同的, //隐式派生自Sy ...
- 通过企业分布式缓存共享运行时数据
许多企业都结合使用 Microsoft .NET Framework 和 Java 应用程序,尤其是那些出于各种考虑不能只依赖于单一技术的大中型企业. 通常,企业采用 Web 应用程序.面向服务的体系 ...
- 1.Containerd容器运行时初识与尝试
0x00 前言简述 1.基础介绍 2.专业术语 3.架构简述 0x01 安装配置 1.Ubuntu安装Containerd.io流程 0x02 简单使用 1.镜像拉取与运行 2.创建和使用网络 3.与 ...
- java编译时多态和运行时多态_运行时多态、编译时多态和重载、重写的关系(不区分Java和C#,保证能看懂!)...
以前在大学学习OOP的时候,知道了重载和重写的区别,但如果要把他们和多态联系起来,我想很多新手朋友和我当初一样是死记的,可是时间长了,自然而然就忘记了,最近在写测试的时候,终于"开窍&quo ...
- 【容器运行时】一文理解 OCI、runc、containerd、docker、shim进程、cri、kubelet 之间的关系
参考 docker,containerd,runc,docker-shim 之间的关系 Containerd shim 进程 PPID 之谜 内核大神教你从 Linux 进程的角度看 Docker R ...
- Java判断数组是递增或者递减_账户对应关系,是指采用复式记账法对每笔交易或事项进行记录时,相关账户之间形成的增加或减少的相互关系。...
[多选题]下列不属于会计信息质量要求的有 ( ) [判断题]共价键的键长等于成键原子共价半径之和. [多选题]关于do while循环,下列说法正确的是(). [单选题]资产按照预计从其持续使用和最终 ...
最新文章
- ​易生信-宏基因组积微学术论坛:基于大数据整合准确预测土壤的枯萎病发生...
- 本田、大众宣布智能路口研究新进展 以安全为重点
- synchronsized修饰方法的使用
- Gamma阶段第九次scrum meeting
- Nginx+Tomcat简单集群配置
- 1.1 VMware 一步一步创建虚拟机
- 走进移动支付:开启物联网时代的商务之门
- 计算机考研:计算机组成原理考点分析
- asp.net core 集成 log4net 日志框架
- 怎样验证软件是否可信?是否被篡改?
- HTML5文件API之FileReader
- 关于Bean Validation
- 什么是Python解释器?
- java编译命令是什么_JAVA命令行编译及运行
- 开源遥感软件(未完待续)
- sql数据库中毒,扩展名被改为.supporthelpgood​,.666decrypt666​​​​​​,.xxxxx,.dom,勒索病毒加密该如何恢复数据
- 迅雷后门 迅雷签名可疑文件 请大家关注 内部邮件大爆料 过全部杀毒软件
- python mysqldb insert_Python MySQLdb 插入数据
- 新年新气象,2021来了,用Python换一张头像迎新年吧!
- 项目成功部署到idea ,并且成功运行,访问却是404
热门文章
- 使用Xcode 6中的AutoLayout约束模拟方面适合行为
- 如何在Windows上的Git Bash中退出'git diff'的结果? [重复]
- 我们如何制作xkcd样式图?
- 您如何轻松地水平居中 div 使用CSS? [重复]
- 怎么调用anaconda安装的pip_对于学python的小伙伴来到底该不该安装andconda
- 360软件管家android,360软件管家
- 路径规划之RRT类算法简述
- python使用ddt_使用DDT数据驱动测试框架Python
- python一个函数调用另一个函数_python下如何在目录下让Python文件去调用另一个文件内的函数或类...
- L1-035 情人节(两种方法)