[.net 面向对象程序设计进阶] (8) 托管与非托管

本节导读:虽然在.NET编程过程当中,绝大多数内存垃圾回收由CLR(公共语言运行时)自动回收,但也有不少须要咱们编码回收。掌握托管与非托管的基本知识,能够有效避免某些状况下致使的程序异常。html

1.什么是托管与非托管?数据库

托管资源:通常是指被CLR(公共语言运行时)控制的内存资源,这些资源由CLR来管理。能够认为是.net 类库中的资源。编程

非托管资源:不受CLR控制和管理的资源c#

对于托管资源,GC负责垃圾回收。对于非托管资源,GC能够跟踪非托管资源的生存期,可是不知道如何释放它,这时候就要人工进行释放。安全

2.哪些资源是非托管的?网络

整体来讲就是 不受CLR控制和管理的资源函数

包括:好比文件流、图像图形类、数据库的链接,网络链接,系统的窗口句柄,打印机资源等,这类资源通常不存在堆上。能够认为操做系统资源的一组API性能

原则:若是咱们的类使用的非托管资源,如数据库链接、文件句柄,这些资源需作到:使用后马上释放。this

3.如何释放非托管资源?编码

.NET对于释放资源,标准作法以下:

1)继承IDisposable接口;

2)实现Dispose()方法在其中释放托管资源和非托管资源,并将对象自己从垃圾回收器中移除(垃圾回收器不在回收此资源);

3 实现类析构函数在其中释放非托管资源。

 对于Dispose()方法的几个参数说明:

A. 参数为true表示释放全部资源,只能由使用者调用

 参数为false表示释放非托管资源,只能由垃圾回收器自动调用

C. 若是子类有本身的非托管资源,能够重载这个函数,添加本身的非托管资源的释放

D.可是要记住,重载此函数必须保证调用基类的版本,以保证基类的资源正常释放

4.举例说明资源释放

4.1 数据库链接释放

(1)错误作法:

   SqlConnection conn = new SqlConnection();

    //do something;

conn.Dispose();

此段代码,若是出现异常conn.Dispose()未能及时执行,会致使没有及时关闭链接。

(2)正确作法:       

SqlConnection conn = new SqlConnection();
try
{
    //do something;
}
finally
{
    conn.Dispose();
}

  对于以上代码,咱们还能够简化代码量,c#使用using简化输入,编译器自动翻译成 try...finally,改成下面写法

(3)改进作法: 

using(SqlConnection conn = new SqlConnection())
{
      //do something;
}

4.2 资源回收综合示例 

public class BaseResource : IDisposable
    {
        private IntPtr handle; // 句柄,属于非托管资源
        private System.ComponentModel.Component comp; // 组件,托管资源
        private bool isDisposed = false; // 是否已释放资源的标志

        //实现接口方法
        //由类的使用者,在外部显示调用,释放类资源
        public void Dispose()
        {
            Dispose(true);// 释放托管和非托管资源

            //将对象从垃圾回收器链表中移除,
            // 从而在垃圾回收器工做时,只释放托管资源,而不执行此对象的析构函数
            GC.SuppressFinalize(this);
        }

        //由垃圾回收器调用,释放非托管资源
        ~BaseResource()
        {
            Dispose(false);// 释放非托管资源
        }

        //参数为true表示释放全部资源,只能由使用者调用
        //参数为false表示释放非托管资源,只能由垃圾回收器自动调用
        //若是子类有本身的非托管资源,能够重载这个函数,添加本身的非托管资源的释放
        //可是要记住,重载此函数必须保证调用基类的版本,以保证基类的资源正常释放
        protected virtual void Dispose(bool disposing)
        {
            if (!this.isDisposed)// 若是资源未释放 这个判断主要用了防止对象被屡次释放
            {
                if (disposing)
                {
                    comp.Dispose();// 释放托管资源
                }               
            }
            this.isDisposed = true; // 标识此对象已释放
        }
    }

5.对于释放资源注意的几点

A. 显示调用Dispose()方法,能够及时的释放资源,同时经过移除Finalize()方法的执行,提升了性能;

B. 若是没有显式调用Dispose()方法,垃圾回收器也能够经过析构函数来释放非托管资源,垃圾回收器自己就具备回收托管资源的功能,从而保证资源的正常释放,只不过由垃圾回收器回收会致使非托管资源的未及时释放的浪费。

C. .NET中应该尽量的少用析构函数释放资源。在没有析构函数的对象在垃圾处理器一次处理中从内存删除,但有析构函数的对象,须要两次,第一次调用析构函数,第二次删除对象。并且在析构函数中包含大量的释放资源代码,会下降垃圾回收器的工做效率,影响性能。

D. 对于包含非托管资源的对象,最好及时的调用Dispose()方法来回收资源,而不是依赖垃圾回收器

E. 析构函数只能由垃圾回收器调用。

F. Despose()方法只能由类的使用者调用。

G. .NET中,凡是继承了IDisposable接口的类,均可以使用using语句,从而在超出做用域后,让系统自动调用Dispose()方法。
H. 一个资源安全的类,都实现了IDisposable接口和析构函数。提供手动释放资源和系统自动释放资源的双保险。

6. 关于Finalize和Dispose

(1)、Finalize只释放非托管资源;

(2)、Dispose释放托管和非托管资源;

(3)、重复调用Finalize和Dispose是没有问题的;

(4)、Finalize和Dispose共享相同的资源释放策略,所以他们之间也是没有冲突的。

7. 要点:

本节内容比较简单,主要了解了.NET托管和非托管两种资源,绝大多部资源由CLR(公共语言运行时)自动释放,称为托管代码;还有一部分资源须要人工释放,称为非托管代码。掌控非托管代码的几种内存释放方法,能够以效的避免程序产生异常,合理释放内存,有利于程序稳定和流畅。

==============================================================================================  

 返回目录

 <若是对你有帮助,记得点一下推荐哦,若有

有不明白或错误之处,请多交流>  

<对本系列文章阅读有困难的朋友,请先看《.net 面向对象编程基础》>

<转载声明:技术须要共享精神,欢迎转载本博客中的文章,但请注明版权及URL>

.NET 技术交流群:467189533    .NET 程序设计

==============================================================================================   

相关文章
相关标签/搜索