CLR管理的内存主要有三块, 也就是我们对象实例分配在这三块内存区域:
1. 线程的堆栈: 用于分配值类型实例, 又操作系统管理, 不受垃圾收集器的控制, 但之类型实例所在的方法结束, 其存储单元自动释放. 栈的执行效率高, 但容量有限.
2. GC堆: 用于分配小于85000字节的引用类型小对象实例. 但有内存分配或垃圾回收时, 垃圾收集器可能会对GC堆压缩.
3. LOH堆: 用于分配不小于85000字节的引用类型大对象实例, LOH堆不会被压缩, 只有在GC堆全部被回收后, LOH堆才会被回收.
我们常说的托管堆就是指GC堆和LOH堆
在.Net中有两大类数据类型, 即值类型和引用类型
1. 值类型(如 、 和 )、枚举类型和结构类型。
上文说到值类型是分配在线程的堆栈中, 但并非所有的值类型都分配在堆栈上. 如: 类是引用类型, 其有一个成员字段是值类型, 则该字段作为引用类型实例的一个成员也和类一样, 被创建在托管堆上. 还如: 在装箱的时候, 值类型也会被copy到托管堆上.
2. 引用类型包括类 (Class) 类型、接口类型、委托类型和数组类型。
引用类型存贮在动态的堆中, 堆是由应用程序控制的可随时申请和释放该空间,在.Net中一般情况下有垃圾收集器处理.如果引用类型嵌套在值类型里的话, 值类型在线程的堆栈上, 而引用类型在GC堆上, 只是对引用类型的引用在线程的堆栈上.
值类型与引用类型的区别在于值类型的变量直接包含其数据,而引用类型的变量则存储对象引用。对于引用类型,两个变量可能引用同一个对象,因此对一个变量的操作可能影响另一个变量所引用的对象。对于值类型,每个变量都有自己的数据副本,对一个变量的操作不可能影响另一个变量。
引用类型实例:
StringBuilder s1 = new StringBuilder();//将StringBuilder的一个首地址传给s1
StringBuilder s2 = s1;//将S1中的首地址传给s2
s2.Append("abc");
Console.WriteLine(s1);
s1 = null;
Console.WriteLine(s2);
输出结果:
abc
abc
说明: "s1 = null"只是将s1的引用置为空, 但此时StringBuilder的堆空间并没有被释放,
因此在此之后,输出s2时,仍然可以输出abc.
联系客服