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#运行时的相互关系相关推荐

  1. C# (类型、对象、线程栈和托管堆)在运行时的相互关系

    在介绍运行时的关系之前,先从一些计算机基础只是入手,如下图: 该图展示了已加载CLR的一个windows进程,该进程可能有多个线程,线程创建时会分配到1MB的栈空间.栈空间用于向方法传递实参,方法定义 ...

  2. .Net运行时的相互关系

    阅读目录 前言 线程堆栈的分配 托管堆上对象的分配 结束语 前言 .Net中的运行时,以及各个类型.对象.线程堆栈以及托管堆之间的关系,在初学者(俺是初学者中的菜鸟 J)看来,有很多是难以理解的东西, ...

  3. 类型,对象,线程栈和托管堆在运行时的相互关系(一)。

    当系统加载一个CLR的进程,进程里面可能有多个线程,这时候系统会给这个进程创建一个大小为1M的线程栈.这个线程栈用来存放方法调用的实参,和方法内部定义的局部变量.下图展示了一个线程栈的栈内存.线程栈的 ...

  4. [CLR via C#]4. 类型基础及类型、对象、栈和堆运行时的相互联系

    原文:[CLR via C#]4. 类型基础及类型.对象.栈和堆运行时的相互联系 CLR要求所有类型最终都要从System.Object派生.也就是所,下面的两个定义是完全相同的, //隐式派生自Sy ...

  5. 通过企业分布式缓存共享运行时数据

    许多企业都结合使用 Microsoft .NET Framework 和 Java 应用程序,尤其是那些出于各种考虑不能只依赖于单一技术的大中型企业. 通常,企业采用 Web 应用程序.面向服务的体系 ...

  6. 1.Containerd容器运行时初识与尝试

    0x00 前言简述 1.基础介绍 2.专业术语 3.架构简述 0x01 安装配置 1.Ubuntu安装Containerd.io流程 0x02 简单使用 1.镜像拉取与运行 2.创建和使用网络 3.与 ...

  7. java编译时多态和运行时多态_运行时多态、编译时多态和重载、重写的关系(不区分Java和C#,保证能看懂!)...

    以前在大学学习OOP的时候,知道了重载和重写的区别,但如果要把他们和多态联系起来,我想很多新手朋友和我当初一样是死记的,可是时间长了,自然而然就忘记了,最近在写测试的时候,终于"开窍&quo ...

  8. 【容器运行时】一文理解 OCI、runc、containerd、docker、shim进程、cri、kubelet 之间的关系

    参考 docker,containerd,runc,docker-shim 之间的关系 Containerd shim 进程 PPID 之谜 内核大神教你从 Linux 进程的角度看 Docker R ...

  9. Java判断数组是递增或者递减_账户对应关系,是指采用复式记账法对每笔交易或事项进行记录时,相关账户之间形成的增加或减少的相互关系。...

    [多选题]下列不属于会计信息质量要求的有 ( ) [判断题]共价键的键长等于成键原子共价半径之和. [多选题]关于do while循环,下列说法正确的是(). [单选题]资产按照预计从其持续使用和最终 ...

最新文章

  1. ​易生信-宏基因组积微学术论坛:基于大数据整合准确预测土壤的枯萎病发生...
  2. 本田、大众宣布智能路口研究新进展 以安全为重点
  3. synchronsized修饰方法的使用
  4. Gamma阶段第九次scrum meeting
  5. Nginx+Tomcat简单集群配置
  6. 1.1 VMware 一步一步创建虚拟机
  7. 走进移动支付:开启物联网时代的商务之门
  8. 计算机考研:计算机组成原理考点分析
  9. asp.net core 集成 log4net 日志框架
  10. 怎样验证软件是否可信?是否被篡改?
  11. HTML5文件API之FileReader
  12. 关于Bean Validation
  13. 什么是Python解释器?
  14. java编译命令是什么_JAVA命令行编译及运行
  15. 开源遥感软件(未完待续)
  16. sql数据库中毒,扩展名被改为.supporthelpgood​,.666decrypt666​​​​​​,.xxxxx,.dom,勒索病毒加密该如何恢复数据
  17. 迅雷后门 迅雷签名可疑文件 请大家关注 内部邮件大爆料 过全部杀毒软件
  18. python mysqldb insert_Python MySQLdb 插入数据
  19. 新年新气象,2021来了,用Python换一张头像迎新年吧!
  20. 项目成功部署到idea ,并且成功运行,访问却是404

热门文章

  1. 使用Xcode 6中的AutoLayout约束模拟方面适合行为
  2. 如何在Windows上的Git Bash中退出'git diff'的结果? [重复]
  3. 我们如何制作xkcd样式图?
  4. 您如何轻松地水平居中 div 使用CSS? [重复]
  5. 怎么调用anaconda安装的pip_对于学python的小伙伴来到底该不该安装andconda
  6. 360软件管家android,360软件管家
  7. 路径规划之RRT类算法简述
  8. python使用ddt_使用DDT数据驱动测试框架Python
  9. python一个函数调用另一个函数_python下如何在目录下让Python文件去调用另一个文件内的函数或类...
  10. L1-035 情人节(两种方法)