堆和栈在不同的地方的概念都不相同。
我说明的是在 c#中的Stack(堆栈)与Heap(托管堆)。
值类型直接存储其值,值保存在 Stack(堆栈)中。
引用类型存储对值的引用,值保存在 Heap托管堆)中。
值类型转为引用类型叫做 装箱,引用类型转为值类型叫 拆箱。
这里最需要搞清楚的是在语言中Stack与Heap指的是内存中的某一个区域,
区别于数据结构中的栈(后进先出的线性表),堆(经过某种排序的二叉树)。
C#堆栈在内存中的活动:
C#托管堆在内存中的活动:
先来说明一下为什么有托管堆?
{
int a=1;
double b = 2.0;
}
//一个大括号中是一个作用域
因为变量a和b都是值类型,1和2.0都直接保存在栈中,由上图中可知在 作用域 结束后,a和b两个变量就会被释放掉。
假设存在其他作用域,在这个作用域中就不能直接读取‘1’这个值。
第3行,分配空间到栈,实例对象bb: bb中在栈没有值,只是一个引用,而不是实际的BB对象。
第4行,分配空间到堆,把BB放进去, bb中在栈中的值就是BB在堆中地址。
假设在第5行前,操作一下bb,例如给bb中的某个字段赋值。bb.a="123456";
走出了这个作用域,会把bb这个实例对象释放掉(bb在栈中指向BB堆中的地址也就被释放了),但在堆中BB的值还是存在的(如:bb.a="123456";)(只有该对象的数据不再被任何变量引用时,它才会被删除。)
以上中作用域结束时,存放在栈中的 值 会直接被释放掉;而在堆中 值 还是会存在(这个值还在被其他实例对象引用),这就是区别。
托管堆的垃圾收集
对象不再被引用时,会删除堆中已经不再被引用的对象。如果仅仅是这样,久而久之,堆上的自由空间就会分散开来,给新对象分配内存就会很难处理,.NET运行库必须搜索整个堆才能找到一块足够大的内存块来存储整个新对象。
但托管堆的垃圾收集器运行时,只要它释放了能释放的对象,就会压缩其他对象,把他们都推向堆的顶部,形成一个连续的块。在移动对象的时候,需要更新所有对象引用的地址,会有性能损失。但使用托管堆,就只需要读取堆指针的值,而不用搜索整个链接地址列表,来查找一个地方放置新数据。
因此在.NET下实例化对象要快得多,因为对象都被压缩到堆的相同内存区域,访问对象时交换的页面较少。Microsoft相信,尽管垃圾收集器需要做一些工作,修改它移动的所有对象引用,导致性能降低,但这样性能会得到弥补
作者:FengYang
博客地址:http://blog.csdn.net/qq_28140365
版权声明:如果感觉文章哪里写的不对或者存在疑问,欢迎留言,共同学习、进步!
蓝色字体为链接
我说明的是在 c#中的Stack(堆栈)与Heap(托管堆)。
值类型直接存储其值,值保存在 Stack(堆栈)中。
引用类型存储对值的引用,值保存在 Heap托管堆)中。
值类型转为引用类型叫做 装箱,引用类型转为值类型叫 拆箱。
这里最需要搞清楚的是在语言中Stack与Heap指的是内存中的某一个区域,
区别于数据结构中的栈(后进先出的线性表),堆(经过某种排序的二叉树)。
C#堆栈在内存中的活动:
如图
C#托管堆在内存中的活动:
先来说明一下为什么有托管堆?
{
int a=1;
double b = 2.0;
}
//一个大括号中是一个作用域
因为变量a和b都是值类型,1和2.0都直接保存在栈中,由上图中可知在 作用域 结束后,a和b两个变量就会被释放掉。
假设存在其他作用域,在这个作用域中就不能直接读取‘1’这个值。
1 void AA()
2 {
3 BB bb;
4 bb= new BB();
5 }
第3行,分配空间到栈,实例对象bb: bb中在栈没有值,只是一个引用,而不是实际的BB对象。
第4行,分配空间到堆,把BB放进去, bb中在栈中的值就是BB在堆中地址。
假设在第5行前,操作一下bb,例如给bb中的某个字段赋值。bb.a="123456";
走出了这个作用域,会把bb这个实例对象释放掉(bb在栈中指向BB堆中的地址也就被释放了),但在堆中BB的值还是存在的(如:bb.a="123456";)(只有该对象的数据不再被任何变量引用时,它才会被删除。)
以上中作用域结束时,存放在栈中的 值 会直接被释放掉;而在堆中 值 还是会存在(这个值还在被其他实例对象引用),这就是区别。
托管堆的垃圾收集
对象不再被引用时,会删除堆中已经不再被引用的对象。如果仅仅是这样,久而久之,堆上的自由空间就会分散开来,给新对象分配内存就会很难处理,.NET运行库必须搜索整个堆才能找到一块足够大的内存块来存储整个新对象。
但托管堆的垃圾收集器运行时,只要它释放了能释放的对象,就会压缩其他对象,把他们都推向堆的顶部,形成一个连续的块。在移动对象的时候,需要更新所有对象引用的地址,会有性能损失。但使用托管堆,就只需要读取堆指针的值,而不用搜索整个链接地址列表,来查找一个地方放置新数据。
因此在.NET下实例化对象要快得多,因为对象都被压缩到堆的相同内存区域,访问对象时交换的页面较少。Microsoft相信,尽管垃圾收集器需要做一些工作,修改它移动的所有对象引用,导致性能降低,但这样性能会得到弥补
作者:FengYang
博客地址:http://blog.csdn.net/qq_28140365
版权声明:如果感觉文章哪里写的不对或者存在疑问,欢迎留言,共同学习、进步!
蓝色字体为链接