托管资源指的是.NET Framework可以自动进行回收的资源,主要是指托管堆上分配的内存资源。非托管资源指的是.NET Framework不知道如何回收的资源,本文主要介绍.NET(C#) 中资源回收相关的垃圾回收器GC、析构函数(Finalize 方法)和Dispose。

1、垃圾回收器GC

GC(Garbage Collection)是.NET中的垃圾回收器。以应用程序的root为基础,遍历应用程序在Heap上动态分配的所有对象,通过识别它们是否被引用,来确定哪些对象是已经死亡的,哪些仍需要被使用。已经不再被应用程序的root或者别的对象所引用的对象就是已经死亡的对象,即所谓的垃圾,需要被回收。GC的开销通常很大,而且它的运行具有不确定性,微软的编程规范里是强烈建议你不要显式调用GC。但你的代码中还是可以使用.NET Framework中GC的某些方法进行手动回收,前提是必须要深刻理解GC的回收原理,否则手动调用GC在特定场景下很容易干扰到GC的正常回收甚至引入不可预知的错误。

在.NET Framework中,创建对象所用内存在托管堆中分配,垃圾管理器负责管理。在堆中可分配的内存,被CLR以块划分,以代[Gemeration]命名,初始分为256k、2M和10M三个代(0、1和2)。并且CLR可以动态调整代的大小。在堆创建的每一个对象都有一个Generation的属性。.NET Framework中约定,最近创建的对象,其Generation其值为0。创建时间越远代数越高。

强制垃圾回收用函数GC.Collect()GC.Collect(int32)参考为Generation,代码如下,

using System; 
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
 
namespace ConsoleApplication
{
    public class TestObject 
    {
      public int Value = 100;
      public string Key = "cjavapy";
    }
    class Program
    {
        static void Main(string[] args)
        {
            TestObject obj  =   new  TestObject();
            int  generation  =   0 ;
             
            generation  =  GC.GetGeneration(obj);
            Console.WriteLine(0);
            Console.WriteLine( " TotalMemory:{0} " , GC.GetTotalMemory( false ));
            Console.WriteLine( " MaxGeneration:{0} " , GC.MaxGeneration);
            Console.WriteLine( " Value:{0},Key:{1} " , obj.Value, obj.Key.Length);
            Console.WriteLine( " Generation:{0} " , generation);
            Console.WriteLine();
             
            try
            {
                new FileStream(@"F:\cavapy.avi", FileMode.Open);
            }
            catch  (Exception e) { }
             
            for  ( int  j  =   1 ; j  <   6 ; j ++ )
            {
                generation  =  GC.GetGeneration(obj);
                Console.WriteLine(j.ToString());
                Console.WriteLine( " TotalMemory:{0} " , GC.GetTotalMemory( false ));
                Console.WriteLine( " MaxGeneration:{0} " , GC.MaxGeneration);
                Console.WriteLine( " Value:{0},Key:{1} " , obj.Value, obj.Key.Length);
                Console.WriteLine( " Generation:{0} " , generation);
                Console.WriteLine();
                GC.Collect();
                GC.WaitForPendingFinalizers();
            }
            Console.ReadKey();  
        }
    }
}

2、析构函数(Finalize 方法)

析构函数(Finalize 方法)用来释放非托管资源,由GC来调用执行回收,来保证非托管资源可以被释放。Object.Finalize()方法是无法重载的,编译器是根据类的析构函数来自动生成Object.Finalize()方法的。对于包含非托管资源的类,可以将释放非托管资源的代码放在析构函数。

例如,

public class FinalizeClass
{
    ~FinalizeClass()
    {
       //在这里,清理非托管资源
    }
}

注意:不能在析构函数中释放托管资源,因为析构函数是由垃圾回收器调用的,可能在析构函数调用之前,类包含的托管资源已经被回收了,从而导致无法预知的结果。

3、Dispose

.NET Framework中非托管理资源的释放,除了可以使用析构函数(Finalize 方法),还可以通过实现IDisposable接口,代码执行完成后通过调用Dispose()方法来释放非托管资源。与析构函数的区别主要是,Dispose()方法需要程序员手动调用。

调用方式如下,

//方式1:显示接口调用
SomeType st1=new SomeType();
//执行操作
st1.Dispose();
 
//方式2:using()语法,运行到using范围外自动执行Dispose方法
using (var st2 = new SomeType())
{
    //执行操作
}

推荐文档