C# 释放非托管资源

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

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

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

 1 MyClass
2 {
3 ~MyClass()
4 {
5 DisposePro();
6 }
7
8 public void Dispose()
9 {
10 DisposePro();
11 }
12
13 private void DisposePro()
14 {
15 // 释非代码
16 ......
17 }
18 }

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

 1   MyClass
2 {
3 private bool disposed = false;
4 ~MyClass()
5 {
6 DisposePro();
7 }
8
9 public void Dispose()
10 {
11 DisposePro();
12 }
13
14 private void DisposePro()
15 {
16 if(disposed == false)
17 {
18 // 释非代码
19 ......
20 }
21 disposed = true;
22 }
23 }

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

 1     MyClass
2 {
3 private bool disposed = false;
4 ~MyClass()
5 {
6 DisposePro();
7 }
8
9 public void Dispose()
10 {
11 DisposePro();
12 }
13
14 private void DisposePro()
15 {
16 if(disposed == false)
17 {
18 // 释托管代码
19 ......
20 // 释非代码
21 ......
22 }
23 disposed = true;
24 }
25 }

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

 1       MyClass
2 {
3 private bool disposed = false;
4 ~MyClass()
5 {
6 Dispose(false);
7 }
8
9 public void Dispose()
10 {
11 Dispose(true);
12 }
13
14 private void Dispose(bool disposing)
15 {
16 if(disposed == false)
17 {
18 if(disposing == true)
19 {
20 // 释托管代码
21 ......
22 }
23 // 释非代码
24 ......
25 }
26 disposed = true;
27 }
28 }

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

 1     MyClass:IDisposable
2 {
3 private bool disposed = false;
4 ~MyClass()
5 {
6 Dispose(false);
7 }
8
9 public void Dispose()
10 {
11 Dispose(true);
12 GC.SuppressFinalize(this);
13 }
14
15 private void Dispose(bool disposing)
16 {
17 if(disposed == false)
18 {
19 if(disposing == true)
20 {
21 // 释托管代码
22 ......
23 }
24 // 释非代码
25 ......
26 }
27 disposed = true;
28 }
29 }

标准清理模式中多了一句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

转自https://www.cnblogs.com/niaomingjian/p/3516083.html

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

  1. 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. ubuntu16.04编译安装imu_tk

    imu_tk代码地址 https://bitbucket.org/alberto_pretto/imu_tk 安装依赖项 sudo apt-get install build-essential cm ...

  2. c# 编程小技巧

    1.对于界面布局,可以考虑使用 wpf,对于传统winfrom来说,tableLayoutPanel1可能是最好的选择. 2.你一定会问,如何使用代码管理大量的按钮,可以使用 List<Butt ...

  3. MQTT 单片机端讲解

    有空了和大家分享一下,如何从头架构一个高效mqtt并行客户端,基于传统GPRS等较差网络环境和网关等网络环境好的情景(当然仔细讲解mqtt的基本函数使很有必要的).---这会正忙着搬砖 MQTt协议 ...

  4. CH 0101 - a^b / CH 0102 - 64位整数乘法 - [快速幂和快速乘]

    0101 a^b 题目链接:传送门 描述 求 a 的 b 次方对 p 取模的值,其中 1≤a,b,p≤10^9 输入格式 三个用空格隔开的整数 a,b 和 p. 输出格式 一个整数,表示 a^b mo ...

  5. [No0000147]深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing)理解堆与栈4/4

    前言   虽然在.Net Framework 中我们不必考虑内在管理和垃圾回收(GC),但是为了优化应用程序性能我们始终需要了解内存管理和垃圾回收(GC).另外,了解内存管理可以帮助我们理解在每一个程 ...

  6. [No0000D5]便利所有子目录更改后缀名bat

    pause for /r %%i in (.) do ( cd %%i ren *.txt *.dll ) pause

  7. zookeeper 杂记

    Zookeeper为了保证高吞吐和低延迟,在内存中维护了这个树状的目录结构,这种特性使得Zookeeper不能用于存放大量的数据,每个节点的存放数据上限为1M.

  8. cxgridchart饼状图

    var VIEW:TcxGridDBChartView; Level:TcxGridLevel; Series:TcxGridDBChartSeries; begin View := cxGrid1. ...

  9. python摸爬滚打之day11----函数闭包,迭代器

    1.函数名 函数名就是一个变量名, 函数名存储的是该函数的内存地址.    函数名都可以进行哪些应用? 函数名可以赋值给其他的变量; 函数名可以作容器里的元素使用; 函数名可以当做形参传进另一函数; ...

  10. python摸爬滚打之day01----初识Python

    1.编程语言分类 编译型语言:程序被一次性全部翻译成机器语言,计算机直接以机器语⾔言来运⾏行行此程序. 优点:运行效率高,可脱离语言环境独立运行. 缺点:开发效率低,可移植性差. 解释型语言:将程序逐 ...