垃圾回收
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了垃圾回收相关的知识,希望对你有一定的参考价值。
CLR管理的内存块
- 线程的堆栈
- GC堆
- LOH(large Object Heap)堆对象大于85000字节
托管堆=GC Heap + Loader Heap
什么样的对象会被回收
GC只回收GC堆中的对象,堆栈的不管
只有当前不可达的对象会被回收
先介绍下应用程序根
这个概念,应用程序根可以是:
- 本地变量或者全局变量(C#不支持全局变量,但CIL允许)
- 类型的静态成员或者静态属性
- 传递到方法中的参数变量
- CPU寄存器所引用的对象
如图中在运行RunTest时, _item
与item
都是应用程序根,但如果RunTest执行完,item则被栈销毁,Phone对象少了一个能引用他的根
但Phone不会被销毁,因为静态变量_item
始终引用着它。
相反,图中对象3与对象4,没有根引用它们,就当前运行环境而言无法获取它们,所以它们就是下一次垃圾回收的对象
怎么回收
就算法而言,GC采用的是mark-and-compact(标记和压缩)
先假设所有对象是可回收,再根据根
找到可达对象,把他添加到可达对象图
(如果可达对象引用了其他对象,那“其他对象”也是可达的),最后将不可达的对象清空,留下的对象重新排布,压缩内存.
在压缩内存时,GC会重新找到一个新的较大的连续空间,将对象复制过来,并修改所有引用
显然这种操作是耗性能的,有时候就是会遇到生命周期比较长的对象,如果频繁地对它垃圾回收,势必会产生很多压缩内存的消耗。
于是GC结合代
的机制提升垃圾回收性能
这种机制的对你的代码做出以下几点假设
- 对象越新,生命周期越短
- 对象越老,生命周期越长
- 回收堆的一小部分,速度快与回收整个堆
该机制将对象分成三代,分别是0,1,2代。每一代的大小依次增大,0代最小,2代最大。
代的大小在运行时也可能会调整,并不是固定的。
新的对象都视为0代,垃圾回收时存活下来的0代会被提升到1代,当0代与1代空间都不足时,1代的对象才会提升到2代(同时0代提升到1代)
什么时候回收
- 调用GC.Colect
- 内存不足(0代满了)
- CLR卸载AppDomain
- CLR关闭
大对象
对象大于85000字节时会保存到LOH(large Object Heap)堆
- 没有代级的概念,所有对象都被视为第2代。
- 不进行对象移动和空间压缩,因为移动大对象是相对耗时的操作。因此,需要一个链
表来维护空闲区域的位置。 - 对象不会被分配在末尾,而会在链表中寻找合适的位置,因此会存在碎片的问题
资料
- 《CLR via in C#》
- 《.Net之美》
- 《你必须知道的.Net》
以上是关于垃圾回收的主要内容,如果未能解决你的问题,请参考以下文章