C#基础之垃圾回收

 

资源分类

  • 托管资源
  • 非托管资源

托管资源

托管资源在.NET Framework中又分别存放在两种地方:堆栈和托管堆。所有的值类型和引用类型的引用都存放在堆栈中,而所有引用所代表的对象实例都保存在堆中。

堆栈的资源出了作用域后会自动释放所占内存;托管堆由CLR(通用语言运行时)的管理,达到一定条件时由垃圾回收机制自动回收资源。

非托管资源

非托管资源包括文件句柄、数据库连接字符串、端口或者其他有限的资源。

非托管资源需要手动回收,常见的有终结器(finalizer)和Dispose。

 

垃圾回收(Garbage Collect,即GC)

GC是.NET Framework等CLI机制的重要部分。基本原理就是使用分代算法等优化方案遍历托管堆中的对象,对还被引用的对象做标记,然后把还在使用的对象转移到一个连续的地址空间,对其余没在使用的对象内存进行回收。

回收步骤

  1. 标记。根据应用程序根指针Root遍历堆上的每一个引用对象,对于还在使用的对象进行标记(其实就是在对象同步索引块中开启一个标示位)。
  2. 清除。对所有没有标记的对象进行清除操作,其中普通对象直接回收内存,而对于实现了终结器的对象需要单独回收处理,第一次回收调用终结器,没有清理对象,第二次回收才真正清理对象。
  3. 整理。垃圾回收后使得内存不连续,出现许多内存碎片,需要把剩下的对象转移到一个连续的内存并更新对象的引用。

分代算法

如果回收垃圾时每次都要遍历托管堆中所有的对象实例,那么性能消耗非常大。分代算法就是垃圾回收机制的一种优化方案。

  • 第0代:一个新对象被实例化并第一次被分配在托管堆上时,就是第0代。 
  • 第1代:0代满了会触发0代的垃圾回收,0代垃圾回收后,剩下的对象就是第1代。 
  • 第2代:当0代、1代满了,会触发0代、1代的垃圾回收,第0代升为第1代,第1代升为第2代。

 

 

终结器

终结器类似于C++中的析构函数,格式如下,

Class TestFinalizer
{
    ...
    ~TestFinalizer()
    {
        //这里进行回收
    }
    ...
}
  • 终结器由垃圾回收器负责调用,不能在编译时确定执行终结器的时间,终结器会在对象最后一次使用之后,并在应用程序正常关闭前的某个时间调用。
  • 终结器不允许传递任何参数,不能重载。

垃圾回收时对终结器的处理

  1. 当CLR在托管堆上分配对象时,GC检查该对象是否实现了终结器。如果是,对象会被标记为可终结的,同时这个对象的指针被保存在名为终结队列的内部队列中。终结队列是一个由垃圾回收器维护的表,它指向每一个在从堆上删除之前必须被终结的对象。
  2. 当GC执行并且检测到一个不被使用的对象时,需要进一步检查终结队列来查询该对象类型是否含有终结器,如果没有则将该对象视为垃圾,如果存在则将该对象的引用移动到另外一张Freachable列表,此时对象会被复活一次。
  3. CLR将有一个单独的高优先级线程负责处理Freachable列表,就是依次调用其中每个对象的Finalize方法,然后删除引用,这时对象实例就被视为不再被使用,对象再次变成垃圾。
  4. 下一个GC执行时,将释放已经被调用Finalize方法的那些对象实例。

优缺点

  • 优点:自动调用。
  • 缺点:性能不好,容易被滥用;非确定性终结;资源没有立即回收;终结器会导致对象复活一次,被GC回收两次才最终完成回收工作。

 

Dispose

Dispose的实现方式就是实现IDisposable接口并重写Dispose(),格式如下

public class TestIDispose: IDisposable
{
    public FileStream stream;

    public void Dispose()
    {
        if (stream!= null)
        {
            stream.Close();
        }
    }
}

调用方式

Dispose需要手动调用,有两种手动调用方式。

1. 显示接口调用

TestDispose obj=new TestDispose();
obj.Dispose();

缺点是很容易忘记调用,导致资源没有及时被释放。

2. using()语法调用,自动执行Dispose接口

using (var obj = new TestDispose())
{
    ...
}

using() 只是一种语法形式,其本质还是try…finally的结构,可以保证Dispose始终会被执行。

优缺点

  • 优点:确定性终结,一旦调用立即回收。
  • 缺点:需要手动调用,一旦忘记调用就会导致资源没有及时被释放

 

 

 

参考链接:

https://www.cnblogs.com/anding/p/5260319.html

https://www.xin3721.com/ArticlecSharp/c12901.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值