zoukankan      html  css  js  c++  java
  • 第十四章、使用垃圾回收和资源管理

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

      创建对象过程

      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方法的作用是清理对象使用的任何资源。

  • 相关阅读:
    Word中如何删除目录页的页码
    在java程序代码中打开文件
    Web程序报错:Error instantiating servlet
    将日期类型数据写入到数据库中
    《将博客搬至CSDN》
    软件测试工程师常见的面试题
    我对需求文档的理解
    简单的学生管理系统,实现增删改查
    如何求两个数的最大公约数
    【转载】LoadRunner监控window系统各项指标详解
  • 原文地址:https://www.cnblogs.com/linhuide/p/5819881.html
Copyright © 2011-2022 走看看