知识大全 C#清理非托管对象[1]
Posted 类型
篇首语:尺有所短;寸有所长。物有所不足;智有所不明。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 C#清理非托管对象[1]相关的知识,希望对你有一定的参考价值。
C#清理非托管对象[1] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
这两天帮助其它项目组Review代码 发现有些地方实现了IDispose接口 同时也发现了一些关于IDispose的问题:
A类型实现了IDispose接口 B类型里面含有A类型的字段 B类型没有实现IDispose接口
一个类里面实现了Finalize终结器 同时也实现了IDispose接口 但在Dispose方法里面没有调用GC SuppressFinalize(this)方法
下面我对以上两个问题分别分析一下 并提出解决方案
问题 :如果A类型里面有非托管资源需要在实现的IDispose接口里面释放 由于B类型没有实现IDispose接口 B类型的使用者要想释放A类型的非托管资源并不方便 这样的话 就有可能忘记了释放A类型的非托管资源
解决方案:
实现B类型的IDispose接口 在Dispose方法里面调用A类型的Dispose方法 这样 B类型的使用者在调用B类型Dispose的同时 就把A类型的Dispose也调用了
问题 :在Dispose方法里面没有调用GC SuppressFinalize(this)方法 会有什么问题呢 这样会导致垃圾回收器不能对 这个类型的对象及时回收 当GC开始工作的时候 它首先将没有终结器的垃圾对象从内存中移除 有终结器的所有对象则添加到一个垃圾队列当中 GC会调用一个新线程来执行这些对象的 终结器 当终结器执行完毕后 这个对象会从队列中被移除 这个对象在队列中移除之后 当GC再次开始工作的时候 这个对象才能够被回收 所以有终结器的对 象会比没有的在内存中保留更长的时间 在后面我会对这里再详细的描述一下
解决方案:
在Dispose方法中调用GC SuppressFinalize(this)方法 这样的话 就不会把有终结器的对象则添加到垃圾队列当中
切入正题
net中 非托管代码清理有两种方式:Finalize方式和Dispose方式
Finalize方式:通过对自定义类型实现一个Finalize方法来释放非通过资源
从 net 开始 C#编译器不能对Finalize进行显示的调用和重写 必须使用析构函数来实现它
class A ~A() 释放资源;上面的代码就是通过Finalize方式来释放资源的跟C++用析构函数释放资源的代码很象
但是它实现方式和C++不同 因为它是由垃圾回收器来管理内存的
大家看到了 用Finalize方式释放非托管资源很简单 但是如果你了解了他的实现方式 你可能就不会选择用它来释放非托管资源
那Finalize方式在 net内部是如何实现的呢?
当GC(垃圾回收器)开始工作的时候 它首先将没有终结器的垃圾对象从内存中移除 有终结器的所有对象则添加到一个终止化队列当中 GC会调用一个 新线程来执行这些对象的终结器 当终结器执行完毕后 这些对象会从队列中被移除 这时候由于这些对象在第一次检测到的时候没有被释放 它们将会进入第 代 对象 直到GC检测到第 代对象和第 代对象再次充满时 这时候GC才会把刚才那些对象释放掉 所以有终结器的对象会比没有的在内存中保留更长的时间
提示:垃圾回收器把托管堆中的对象分为 代 分别是 一般分配为: 代约 K 代约是 MB 第 代约是MB 代龄越高 容量就越 大 显然效率也就越低 首先被添加到托管堆中的对象被定为第 代 当第 代充满时 就会执行垃圾回收 未被回收的对象代领将提升 代
由于以上原因应该避免仅使用Finalize方式释放非托管资源
Dispose模式:在自定义类中实现IDispose接口 在接口中的Dispose方法中对非托管资源进行释放 闲话少说 上代码
public class MyResourceRelease: IDisposable /// 保证资源只用释放一次 private bool _alreadyDisposed = false; /// 用来判断释放资源的类别(托管和非托管) protected virtual void Dispose(bool isDisposing) if(_alreadyDisposed) return; if(isDisposing) //释放托管资源 //释放非托管资源 _alreadyDisposed = true; public void Dispose() Dispose(true);上面的代码就是用Dispose方式释放资源的方法 因为上面自定义的Dispose(bool isDisposing)方法是virtual的 所以还可以在派生类里面对它进行override
cha138/Article/program/net/201311/15535相关参考
c#使用dllimport调用c++生成的dll库文件报错 报错信息为 对PInvoke函数xxx的调用导致堆栈不对称原因可能是托管的PInvoke签名与非托管的目标签名不匹配请检查PInvo
背景这两天帮助其它项目组Review代码发现有些地方实现了IDispose接口同时也发现了一些关于IDispose的问题:  
C和C++有很多好的类库的沉淀在NET中完全抛弃它们而重头再来是非常不明智的也是不现实的所以我们经常需要通过Pinvoke来使用以前遗留下来的非托管的dll就NET中使用非托管的dll经验而言经常
C++/CLI中有效使用非托管并列缓存 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!VisualS
ASP.NET技巧:非托管COM组件的使用 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 众所周
了解C#特性:对象集合初始化器[1] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 在写一些实体
知识大全 C#开源轻量级对象数据库NDatabase介绍[1]
C#开源轻量级对象数据库NDatabase介绍[1] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
叩开C#之门系列之C#与面向对象编程语言 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! C#是纯
用C#创建COM对象 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 在本篇文章中我们将讨论下面的
C#数组排序与对象大小比较 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! &