基本概念
CLR:公共语言运行时,类似Java的jvm,是直接建立在OS上的虚拟环境,主要任务是管理代码运行。CLR现在支持几十种现代的编程语言为它编写代码,然后以一种中间语言(Intermediate Langeoage,IL)代码的形成被执行。
.Net CLR非常详细讲解了clr原理东西。
线程堆栈:用于分配值类型实例。堆栈主要由操作系统管理,而不受垃圾收集器的控制,当值类型实例所在方法结束时,其存储单位自动释放。执行效率高,但存储容量有限。
GC堆:用于分配小对象实例。如果引用类型对象的实例大小小于85000字节,实例将被分配在GC堆上,当有内存分配或者回收时,垃圾收集器可能会对GC堆进行压缩。
LOH堆:用于分配大对象实例。如果引用类型对象的实例大小不小于85000字节时,该实例将被分配到LOH堆上,而LOH堆不会被压缩,而且只在完全GC回收时被回收。
TypeHandle(类型句柄):指向对应实例的方法表,每个对象创建时都包含该附加成员,并且占用4个字节的内存空间。我们知道,每个类型都对应于一个方法表,方法表创建于编译时,主要包含了类型的特征信息、实现的接口数目、方法表的slot数目等。
NextObjPtr:由托管堆维护的一个指针,用于标识下一个新建对象分配时在托管堆中所处的位置。CLR初始化时,NextObjPtr位于托管堆的基地址
分配原则
.Net中的资源分为托管资源(受clr管理)和非托管资源(不受clr管理),取决于变量的数据类型,托管资源被存放在托管堆和堆栈中。
托管资源数据类型分为值类型和引用类型,关于两者的联系,之前的博客 【傻傻分不清楚】C#值类型、引用类型 做了比较。
值类型实例
对于值类型的实例,CLR在运行时有两种分配方式:(1) 如果该值类型的实例作为类型中的方法(Method)中的局部变量,则该实例被创建在线程栈上;(2) 如果该值类型的实例作为类型的成员,则该实例作为引用类型(引用类型在GC堆或者LOH上创建)的实例的一部分,被创建在GC堆上
public class Test1
{
private int i;
//上面(2)中的情况,生成Test的实例的同时,int类型的实例i被创建在GC堆上
public Test1()
{
byte b =0;
//(1)中的情况,byte类型的实例b被创建在执行这段代码的线程栈上
}
}
引用类型实例
对于引用类型的实例,CLR在运行时也有两种分配方式:(1) 如果该引用类型的实例的Size<85000Byte,则该实例被创建在GC(Garbage Collection)堆上(当CLR在分配和回收对象时,GC可能会对GC堆进行压缩);(2) 如果该引用类型的实例的Size>=85000byte,则该实例被创建在LOH(Large Object Heap)上(LOH不会被压缩)。
public class Test2
{
private int[] intArr;
public Test2()
{
private Object o = new Object();
//引用o存在线程栈上,它指向GC堆上的Object实例
intArr = new int[21250];
//符合(2)中的Size条件,int数组的实例被创建在LOH上
}
}
有大神写的博客,.NET下的内存分配机制做了非常详细的分析!