C#中资源分为托管资源和非托管资源。 托管资源由垃圾回收器控制如何释放,不需要程序员过多的考虑(当然也程序员也可以自己释放)。 非托管资源需要自己编写代码来释放。那么编写好的释放非托管资源的代码(释非代码)由谁来调用呢。有两种实现方式:

一 将释非代码放到构造函数析构函数中,由系统自动调用,系统会在资源对象不再使用了,会在某个时间调用构造函数析构函数来释放非托管资源。构造函数析构函数的目的就是用来释放或清理非托管资源的。但它有一个问题是调用的时间是系统说了算,不能在程序中自己想要调用时调用析构函数,这是C#规定的。那么就产生了第二种方式。

二 将释非代码放到另外一个函数中,当自己想调用时就调用。将释非代码放在一个方法中共用,代码如下:

 MyClass
{
~MyClass()
{
DisposePro();
} public void Dispose()
{
DisposePro();
} private void DisposePro()
{
// 释非代码
......
}
}

但是这样可能会产生其他问题。资源可能会被多次释放,而产生问题。系统会自动调用析构函数,自己也可能多次调用Dispose()方法。那么解决方法是使用一个全局变量作为标记,来标记资源是否已经被释放,已经释放就不再释放。代码如下:

   MyClass
{
private bool disposed = false;
~MyClass()
{
DisposePro();
} public void Dispose()
{
DisposePro();
} private void DisposePro()
{
if(disposed == false)
{
// 释非代码
......
}
disposed = true;
}
}

这样看起来似乎没有问题了。但是当调用Dispose()方法只能立即释放非托管资源,而托管资源还是需要由GC自动处理。那么为了能够做到调用Dispose()方法时也能够释放立即释放托管资源,则需要在DisposePro()方法中添加上想要释放的托管资源的释放代码(释放托管代码)。代码如下:

     MyClass
{
private bool disposed = false;
~MyClass()
{
DisposePro();
} public void Dispose()
{
DisposePro();
} private void DisposePro()
{
if(disposed == false)
{
// 释托管代码
......
// 释非代码
......
}
disposed = true;
}
}

这样还是有问题,当析构函数调用DisposePro()时,会调用释托管代码,可能产生问题——托管对象可能已经被GC删除了而产生问题。那么使用一个标记给DisposePro(),当是被析构函数调用时不执行释托管代码。重新命名DisposePro(),代码如下:

       MyClass
{
private bool disposed = false;
~MyClass()
{
Dispose(false);
} public void Dispose()
{
Dispose(true);
} private void Dispose(bool disposing)
{
if(disposed == false)
{
if(disposing == true)
{
// 释托管代码
......
}
// 释非代码
......
}
disposed = true;
}
}

用这段代码来释放资源应该没有问题了。看一下标准清理模式,代码如下:

     MyClass:IDisposable
{
private bool disposed = false;
~MyClass()
{
Dispose(false);
} public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
} private void Dispose(bool disposing)
{
if(disposed == false)
{
if(disposing == true)
{
// 释托管代码
......
}
// 释非代码
......
}
disposed = true;
}
}

标准清理模式中多了一句GC.SuppressFinalize(this);【该方法通知CLR不要调用该方法的析构函数,因为它已经被清理了。】如果没有这句代码,我认为不影响程序的正确性,不会发生安全问题,他只是告诉系统不要再调用构造函数了。那么为什么要加上这句代码呢?如果在调用了Dispose()之后再调用析构函数只是多此一举,所以告诉系统不要再调用了。这一点应该和性能有关系。【如果不需要构造函数就不要执行构造函数,他们会带来性能上的开销】。

参考:

C#4.0 图解教程 Daniel M. Solis

相关链接:

1. 实现 Finalize 和 Dispose 以清理非托管资源 http://msdn.microsoft.com/zh-cn/library/b1yfkh5e(v=vs.90).aspx

2. GC.SuppressFinalize 方法 http://msdn.microsoft.com/zh-cn/library/system.gc.suppressfinalize(v=vs.90).aspx

C# 释放非托管资源的更多相关文章

  1. 6.C# 释放非托管资源2

    C# 释放非托管资源 C#中资源分为托管资源和非托管资源. 托管资源由垃圾回收器控制如何释放,不需要程序员过多的考虑(当然也程序员也可以自己释放). 非托管资源需要自己编写代码来释放.那么编写好的释放 ...

  2. 5.C#释放非托管资源1

    释放非托管资源 在介绍释放非托管资源的时候,我觉得有必要先来认识一下啥叫非托管资源,既然有非托管资源,肯定有托管资源. 托管资源指的是.net可以自棕进行回收的资源,主要是指托管堆上分配的内存资源.托 ...

  3. C#编程(七十四)----------释放非托管资源

    释放非托管资源 在介绍释放非托管资源的时候,我觉得有必要先来认识一下啥叫非托管资源,既然有非托管资源,肯定有托管资源. 托管资源指的是.net可以自棕进行回收的资源,主要是指托管堆上分配的内存资源.托 ...

  4. Dispose模式释放非托管资源

    实现方式用的是设计模式里的模板模式,基类先搭好框架,子类重写void Dispose(bool disposing) 即可. 需要注意的是基类的Finalize函数也就是析构函数调用的是虚函数void ...

  5. [转]在C#中使用托管资源和非托管资源的区别,以及怎样手动释放非托管资源:

    托管资源指的是.NET可以自动进行回收的资源,主要是指托管堆上分配的内存资源.托管资源的回收工作是不需要人工干预的,有.NET运行库在合适调用垃圾回收器进行回收. 非托管资源指的是.NET不知道如何回 ...

  6. IDisposable?释放非托管资源接口

    原文:https://www.cnblogs.com/luminji/archive/2011/03/29/1997812.html IDisposable高级篇:https://docs.micro ...

  7. .net 资源释放(托管资源和非托管资源)

    1.托管资源 像int.float.DateTime等都是托管资源:net中80%的资源都是托管资源: 托管资源的回收通过GC(垃圾回收器)自动释放分配给该对象的内存,但无法预测进行垃圾回收的时间,我 ...

  8. C# 托管非托管资源释放

    1.C#几乎所有对象都为托管对象,不同点是有的对象封装了非托管资源. 2.C#大部分对象在进行垃圾回收时都可以回收,包括非托管资源,因为非托管资源都已经通过C#类进行了封装,会将非托管资源的释放放在析 ...

  9. .NET 清理非托管资源

    Dispose 类型的 Dispose 方法应释放它拥有的所有资源.它还应该通过调用其父类型的 Dispose 方法释放其基类型拥有的所有资源.该父类型的 Dispose 方法应该释放它拥有的所有资源 ...

随机推荐

  1. HDU5099——Comparison of Android versions(简单题)(2014上海邀请赛重现)

    Comparison of Android versionsProblem DescriptionAs an Android developer, itˇs really not easy to fi ...

  2. 转载:【译】Android: 自定义View

    简介 每天我们都会使用很多的应用程序,尽管他们有不同的约定,但大多数应用的设计是非常相似的.这就是为什么许多客户要求使用一些其他应用程序没有的设计,使得应用程序显得独特和不同. 如果功能布局要求非常定 ...

  3. highcharts 结合phantomjs纯后台生成图片系列二之php2

    上篇文章中介绍了phantomjs的使用场景,方法. 本篇文章详细介绍使用php,highcharts 结合phantomjs纯后台生成图片.包含一步步详细的php代码 一.highcharts 结合 ...

  4. 3、REST风格的URL

    1.概述 HTTP协议里面,四个表示操作方式的动词:GET.POST.PUT.DELETE,它们分别对应四种基本的操作,GET用来获取资源,POST用来新建资源,PUT用来更新资源,DELETE用来删 ...

  5. 第三章:推荐系统冷启动与CB

    3.1冷启动问题简介: 冷启动问题(cold start)主要分三类: •     用户冷启动 •     物品冷启动 •     系统冷启动 参考解决方案: •     推热门 •     利用用户 ...

  6. struts2更新版本操作有关事项备注

    struts2更新版本操作有关事项备注, 更新主要jar包:struts2-convention-plugin-version,struts2-core-version, struts2-spring ...

  7. HBase学习笔记

    关键类: HBaseAdmin 管理Hbase的,主要负责DDL操作 HTable 管理表中数据,主要负责DML操作 1.为了避免热点,更多的建表方法 在Shell中: },{SPLITS=>[ ...

  8. Space and GridLayout 教程

    Ice Cream Sandwich (ICS) sports two new widgets that have been designed to support the richer user i ...

  9. Android Handler 避免内存泄漏的用法总结

    Android开发经常会用到handler,但是我们发现每次使用Handler都会出现:This Handler class should be static or leaks might occur ...

  10. uva 10131 Is Bigger Smarter ? (简单dp 最长上升子序列变形 路径输出)

    题目链接 题意:有好多行,每行两个数字,代表大象的体重和智商,求大象体重越来越大,智商越来越低的最长序列,并输出. 思路:先排一下序,再按照最长上升子序列计算就行. 还有注意输入, 刚开始我是这样输入 ...