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()) { //执行操作 }