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