C#垃圾回收机制(GC)基础到进阶
什么是GC
GC就是垃圾回收机制(Garbage Collection)是.net框架中一个重要的特性,负责自动管理和释放内存,相比于C++减轻了工作量不需要再去关注于内存。GC的主要目标是回收不再使用的对象所占用的内存资源,避免内存泄漏,减少手动管理内存带来的问题。GC是由Common Language Runtime提供的自动内存管理系统的一部分。
垃圾回收器通过跟踪所有被引用的对象来确定哪些对象是可以进行回收的。从应用程序的root(如静态字段、局部变量)为基础开始遍历,遍历应用程序在heap上动态分配的所有对象。找到所有可达的对象,并将其标记为活动对象,然后清除掉不可达的对象。这就是GC的工作原理。
回收过程--标记压缩算法
- 先假设heap中所有对象都是可以回收,然后找出不能回收的对象,给这些对象打上标记,最后清除掉heap中没有打标记的对象
- Compact阶段:对象回收之后heap内存空间变得不连续,在heap中移动这些对象,使他们重新从heap基地址开始连续排列,类似于磁盘空间的碎片整理
分代回收原理(Generational GC)
GC算法的设计考虑到了4个因素
- 对于较大内存的对象,频繁的GC将耗费大量的资源,成本高且效果差
- 大量新创建的对象生命周期都较短,老对象的生命周期都比较长
- 小部分的进行GC比大块的进行GC效率更高,消耗更少
- 新创建的对象在内存分配上多为连续,且关联程度较强,关联度较强有利于CPU Cache命中
基于上面考虑到的因素,托管堆被分为了三个年龄层
| Gen 0 | 新创建的小对象(初始大小~256KB) |
| Gen 1 | Gen 0回收幸存对象(缓冲区作用) |
| Gen 2 | 长期存活对象(可能达GB级) |
在Gen 0heap内存达到阈值,则触发0代GC,0代GC后Gen 0中幸存的对象进入Gen1。如果Gen 1的内存达到阀值,则进行1代GC,1代GC将Gen 0 heap和Gen 1 heap一起进行回收,幸存的对象进入Gen2。2代GC将Gen 0 heap、Gen 1 heap和Gen 2 heap一起回收 。在net运行期间,2代、1代和0代的频率大致为1:10:100
Finalization Queue和Freachable Queue
这两个队列和.net对象所提供的Finalize方法有关。这两个队列并不用于存储真正的对象,而是存储一组指向对象的指针。当程序中使用了new操作符在Managed Heap上分配空间时,GC会对其进行分析,如果该对象含有Finalize方法则在Finalization Queue中添加一个指向该对象的指针。在GC被启动以后,经过Mark阶段分辨出哪些是垃圾。再在垃圾中搜索,如果发现垃圾中有被Finalization Queue中的指针所指向的对象,则将这个对象从垃圾中分离出来,并将指向它的指针移动到Freachable Queue中。这个过程被称为是对象的复生(Resurrection),本来死去的对象就这样被救活了。为什么要救活它呢?因为这个对象的Finalize方法还没有被执行,所以不能让它死去。专用终结器线程定期扫描Freachable Queue,依次调用队列中对象的Finalize()方法,调用完成之后将对象移出队列。在下一次GC运行的时候,发现object已执行过Finalize()方法,而且不可达,就会彻底回收其内存
托管资源
.net 中的所有类型都是直接或者间接 从System.Object类型派生来的
定义:完全由CLR生命周期管理的对象
主要特征:
- 内存分配在托管堆
- GC自动回收内存
- 无需开发者主动释放
常见示例:类实例对象、基础类型包装类、纯.net对象、委托和事件
非托管资源:
ApplicationContext,Brush,Component,ComponentDesigner,Container,Context,Cursor,FileStream,Font,Icon,Image,Matrix,Object,OdbcDataReader,OleDBDataReader,Pen,Regex,Socket,StreamWriter,Timer,Tooltip ,文件句柄,GDI资源,数据库连接等等资源。可能在使用的时候很多都没有注意到!
.NET的GC机制有这样两个问题:
首先,GC并不是能释放所有的资源。它不能自动释放非托管资源。
第二,GC并不是实时性的,这将会造成系统性能上的瓶颈和不确定性。
GC并不是实时性的,这会造成系统性能上的瓶颈和不确定性。所以有了IDisposable接口,IDisposable接口定义了Dispose方法,这个方法用来供程序员显式调用以释放非托管资源。使用using 语句可以简化资源管理。因为using语句会自动调用dispose,无需手动释放,重复释放可能会导致引发ObjectDisposedException

浙公网安备 33010602011771号