第十四章、使用垃圾回收和资源管理

  值类型离开作用域就会被销毁,内存会被回收。

  创建对象过程

  Square mySquare = new Square ();

  new 表面上是单步操作,但实际要分两步走

  1、首先,new操作从堆中分配原始内存。这个阶段无法进行任何干预。

  2、然后,new操作将原始内存转换成对象;它必须初始化对象。可用构造器控制这一阶段。

  销毁对象过程

  1、CLR(Common Language Runtime)执行清理工作,可以写一个析构器加以控制。

  2、CLR将对象占用的内存归还给堆,解除对象内存的分配。对这个阶段你没有控制权。

  销毁对象并将内存归还给堆的过程称为垃圾回收

  C#完全由CLR控制何时销毁对象。

  编写析构器(析构器只有在对象被垃圾回收时才运行)

  使用析构器,可以在对象被垃圾回收时执行必要的清理工作。析构器肯定会运行,只是不保证在什么时间运行。

  和构造器相似,析构器也是一个特殊的方法,只是CLR会在对象的所有引用都消失之后调用它。析构器的语法是先写一个~符号,然后添加类名。

  class FileProcessor{

  FileStream file = null;

  public FileProcessor(string fileName){

  this.file = File.OpenRead(fileName);//打开文件来读取

  }

  ~FileProcessor()   //析构器

  {

  this.file.Close();//关闭文件

  }

  }

  析构器存在下面这些非常重要的不足:

  1、析构器只适合引用类型。值类型(例如结构)中不能声明析构器。

  2、不能为析构器指定访问的修饰符(例如public)。这是由于永远不在自己的代码中调用析构器——总是由垃圾回收器(CLR的一部分)帮你调用。

  3、析构器不能获取任何参数。

  编译器内部自动将析构器转换成对Object.Finalize方法的一个重写版本的调用。例如:

  编译器将以下析构器:

  class FileProcessor{

  ~FileProcessor()   //析构器

  {

  //这里放你的代码

  }

  }

  转换成以下形式:

  class FileProcessor{

  protected override void Finalize()

  {

  try{//这里放你的代码}

  finally{base.Finalize}

  }

  }

  注意:只有编译器才能进行这个转换。你不能自己重写Finalize,也不能自己调用Finalize。

  为什么要使用垃圾回收器

  在C#中,你永远不能亲自销毁对象。没有任何语法支持这个操作。相对,CLR在它认为合适的时间帮你做这件事情。

  对象的生存期管理是相当复杂的一件事情,这正是C#的设计者决定禁止由你销毁对象的原因。如果程序员负责销毁对象,迟早会遇到以下情况之一:

  1、忘记销毁对象。

  2、试图销毁对象,造成一个或多个变量容纳对象已销毁的对象的引用,即所谓的虚悬引用。

  3、试图多次销毁同一对象。

  在C#这种将可靠性和安全性摆在首要位置的语言中,这些问题当然是不能接受的。取而代之的是,必须由垃圾回收器负责销毁对象。垃圾回收器能做出以下几点担保:

  1、每个对象都会被销毁,它的析构器会运行。

  2、每个对象只被销毁一次。

  3、每个对象只有在它不可抵达时(不再有该对象的任何引用)才会被销毁。

  慎用析构器:写包含析构器的类,会使代码和垃圾回收过程变复杂。此外i,还会影响程序的运行速度。如果程序不包含任何析构器,垃圾回收器就不需要将不可抵达的对象放到freachable队列并对它们进行“终结”(也就是不需要运行析构器)。显然,一件事情做和不做相比,不做会快一些。所以,除非确有必要,否则请尽量避免使用析构器。例如,可以改为使用using语句。

  资源管理

  有时在析构器中释放资源并不明智。有的资源过于宝贵,用完后应马上释放,而不是等待垃圾回收器在某个不确定的时间释放。内存、数据库连接和文件句柄等稀缺资源应尽快释放。这时唯一的选择就是亲自释放资源。这是通过自己写的资源管理方法来实现的。可显示调用类的资源清理方法,从而控制释放资源的时机。

  using语句提供了一个脉络清晰的机制来控制资源的生存周期。可以创建一个对象,这个对象会在using语句块结束时销毁。

  using语句的语法如下:

  using(类型 变量 = 初始化)

  {

  语句块

  }

  下面是确保代码总是在TextReader上调用Close的最佳方式:

  using (TextReader reader = new StreamReader(filename))

  {

  string line;

  while((line = reader.ReadLine()) != null)

  {

  Console.WriteLine(line);

  }

  }

  这个using语句完全等价于一下形式:

  {

  TextReader reader = new StreamReader(filename);

  try{

  string line;

  while((line = reader.ReadLine()) != null)

  {

  Console.WriteLine(line);

  }

  finally

  {

  if(reader != null)

  {

  ((IDisposable)reader).Dispose();

  }

  }

  }

  using语句声明的变量的类型必须实现IDisposable接口。IDisposable接口在System命名空间中,只包含一个名为Dispose的方法。

  namespace System

  {

  interface IDisposable

  {

  void Dispose();

  }

  }

  Dispose方法的作用是清理对象使用的任何资源。

原文地址:https://www.cnblogs.com/linhuide/p/5819881.html