




已阅读5页,还剩4页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
摘 要经过上一章的讨论,我们知道,CLR会在必要的时候启动垃圾回收器对不再使用的对象所占的内存进行回收,其实,在一个对象被回收前我们还可以通过析构函数来实现终结操作释放资源,了解终结操作后,我们还可以使用Dispose模式进行手工强制清理资源。这一章我们将讨论这些相关话题。第一节 析构函数和Finalize方法C#与C+有着类似的析构函数,都是对资源进行清理,但是,在C+中,开发人员明确知道析构函数会被调用,而C#中,开发人员不太明确析构函数会在什么时候被调用,它是由CLR管理的,通常是在一个对象被标记为垃圾对象,如果有析构函数,CLR的垃圾回收器会先调用析构函数,然后再回收其内存。类型System.Object有一个受保护的虚方法protected virtual void Finalize();这个就是“析构函数”。如果想为一个类型添加析构函数,必须使用与C+类型的语法结构:前置波浪线+类名,相当于无参构造函数的名前加上波浪线,如下: public class Code_12 : IApp public void DoWork() Code_12() Console.WriteLine(Clear Code_12); 析构函数前不能有任何访问修饰符,并且一个类型只能有一个析构函数。编译后,上面的Code_12()被编译成名为Finalize的方法可以看到,编译过程实际上是对基类Object的虚方法Finalize()的重写,可以非常强悍地认为Finalize就是析构函数Code_12()的别名, 二者只是书写方式不同,干的都是一样的擦屁股的活。我们再来看一下它的内部IL:.method family hidebysig virtual instance void Finalize() cil managed / 代码大小 25 (0x19) .maxstack 1 .try IL_0000: nop IL_0001: ldstr Clear Code_12 IL_0006: call void mscorlibSystem.Console:WriteLine(string) IL_000b: nop IL_000c: nop IL_000d: leave.s IL_0017 / end .try finally IL_000f: ldarg.0 IL_0010: call instance void mscorlibSystem.Object:Finalize() IL_0015: nop IL_0016: endfinally / end handler IL_0017: nop IL_0018: ret / end of method Code_12:Finalize可以看到,Finalize()方法内实际上是将代码包装到tryfinally块内,我们实现的代码被放到了try块,在finally块内调用了基类的Finalize方法,相当于base.Finalize()。前面我们说过, 析构函数是在垃圾回收器回收垃圾对象之前的最后才执行一些清理工作,它的执行是受CLR管理,非人工可控,我们通过一个示例代码来看一下它的执行顺序: public class Code_12_01 public Code_12_01() Console.WriteLine(Create Code_12_01); Code_12_01() Console.WriteLine(Clear Code_12_01); public class Code_12_02 : Code_12_01 public Code_12_02() Console.WriteLine(Create Code_12_02); Code_12_02() Console.WriteLine(Clear Code_12_02); public class Code_12_03 : Code_12_02 public Code_12_03() Console.WriteLine(Create Code_12_03); Code_12_03() Console.WriteLine(Clear Code_12_03); 执行以下代码,先创建,再遗弃,最后垃圾回收: public void DoWork() Code_12_03 temp = new Code_12_03(); temp = null; /遗弃对象,等待垃圾回收 GC.Collect(); 打印结果:Create Code_12_01Create Code_12_02Create Code_12_03Clear Code_12_03Clear Code_12_02Clear Code_12_01在调用析构函数过程中,是从派生类逐级向上调用基类的析构函数。CLR对这种在垃圾回收前调用对象的析构函数进行资源清理的工作就是终结操作。我们不能控制垃圾回收,同样也不能控制终结操作,调用GC.Collect();只是向CLR发出垃圾回收的请求,垃圾回收器对一第列对象回收的先后顺序,我们是无法控制的。第二节 终结操作在我们平时开发工作中,或多或少都会用到本地资源,如打开文件,网络连接等,对这些资源的操作实际上是CLR通过Windows获取资源的独占句柄,使用完后,必须释放句柄,否则其他访问者将无法使用,例如我们经常碰到的异常“文件XXX正常由另一进程使用,因此该进程无法访问该文件。”就是这种原因造成的。终结操作就是利用析构函数来释放/清理资源,在对象被垃圾回收前,CLR调用Finalize()方法做清理工作,前提是我们提供了析构函数。这通常在我们定义类型中使用到本地资源的时候非常有用。如下一个文件管理类: public class FileManager FileStream fs = null; public FileManager() FileManager() if (fs != null) fs.Close(); 在调用析构函数中,应该确保其内部不该出异常,其实前一节中Code_12()的IL代码也可以看出来,并没有与try对应的catch块。所以我们在FileManager()内对fs进行了判空。垃圾回收器发现FileManager对象不再可用时,会调用Finalize(),在内部关闭fs,接着就是回收其内存了。通常在有垃圾回收的时候都有可能调用Finalize()方法。事实上,在实现了Finalize()的对象内存被回收过程并不是如此简单,这个终结操作有时可能须要执行两次或更多次垃圾回收才能达到释放其内存的目的,继续往下看。先来看两个垃圾回收器管理的列表:终结列表(Finalization List):放置所有实现了Finalize()方法的对象的指针。Frachable队列:放置已被认定为垃圾对象且实现了Finalize()的对象的指针,这里的指针是从终结列表中移过来的。如果类型实现了Finalize(),在创建该类型对象前,即调用构造器之前,CLR会将该对象的一个指针放到一个终结列表(Finalization List)中,终结列表是由垃圾回收器管理的一个数据结构。在一次垃圾回收前,垃圾回收器会标记所有的不可达对象,这时所有的不可达对象已经被判了“死刑”,接着扫描终结列表以查找实现了Finalize()方法的对象的指针,并将这些指针从终结列表中移到Frachable队列中,当Frachable队列不为空时,CLR有一个专门的线程来负责调用队列中指针对应对象的Finalize方法,为了能够调用这些对象的Finalize()方法,必须重新激活这些对象,也就是从“不可达”状态变成“可达”状态,这个过程是使对象复活的过程,调用完Finalize()方法后,该对象就彻底完蛋了,接着就是等待下一次垃圾回收时对其内存进行回收,它永远再无出头之日了(当然,如果在析构函数中把该对象的指针放到一个其他静态变量中,那情况就不一样了。有兴趣的可以自己测试一下。)。在这个过程中,假如对象已被标记为垃圾,但未调用其Finalize方法前,该对象可能被从第0代提升为第1代,则有可能要经过更多次垃圾回收才能释放其内存。GC类提供了一个静态方法GC.WaitForPendingFinalizers(), 此方法将挂起当前线程,接着垃圾回收器清空Frachable队列并调用其中对象的Finalize()方法,全部调用完毕后被挂起的线程才得以恢复。前面的描述中我们知道,即使调用了Finalize()方法也不一定能立即释放该对象的内存,所以可以在GC.WaitForPendingFinalizers()方法后立即跟一个GC.Collect()进行回收,但微软不建议我们不这么干。第三节 使用Dispose模式在上面的讨论中,我们知道Finalize方法是受CLR管控的,也就是一个类型的本地资源在什么时候得到清理,我们并不太清楚,有没有一种方法可以让我们对其方便地控制呢?当然有!那就是实现Dispose模式。接口System.IDisposeable提供了对Dispose模式实现的最佳实践。 public interface IDisposable void Dispose(); 通过实现这个接口,我们可以方便规范地来管理包装了本地资源的类对象,这个模式起到了双重保险的作用,可以分别清理托管和非托管资源。像TextReader、FileStream、WinForm窗体都实现了这个接口,这里我们推荐MSDN上面的实现方式。我们继续对上面的FileManager类进行改造: public class FileManager : IDisposable private bool disposed = false; /非托管资源 private IntPtr handle; /托管资源 FileStream fs = null; public FileManager() FileManager() /GC调用,终结 Dispose(false); public void Dispose() /显示关闭 Dispose(true); /通知GC不必再调用Finalize() GC.SuppressFinalize(this); protected virtual void Dispose(bool disposing) if (!this.disposed) if (disposing & fs != null) / 释放托管资源 fs.Dispose(); /释放非托管资源 /. handle = IntPtr.Zero; disposed = true; 除了实现接口的Dispose()方法,还创建了一个通用的方法Dispose(bool disposing) ,在此方法内,如果对象已经被清理,则不再做清理工作。有两点要注意:(1)Dispose()方法内部,传递了一个true值告诉Dispose(bool disposing)方法此次调用是手工调用,接着使用一个静态方法GC.SuppressFinalize(this);告诉垃圾回收器,此对象我已经手工调用清理资源的方法,你不必再调用Finalize()方法了。(2)FileManager()方法内是传一个false值告诉Dispose(bool disposing)此对象是通过垃圾回收器清理资源的。也就是说,对于FileManager对象,如果你手工调用了清理的方法,则会对托管和非托管方法进行清理,如果你忘记了手工调用,垃圾回收器还是会通过调用Finalize()方法对非托管资源进行清理。第四节 使用using一般地,对于实现了IDisposeable接口的类型对象,在使用完毕后我会在finally块中调用Dispose方法来释放资源。如下: FileManager fs = null; try /fs. finally if (fs != null) fs.Dispose(); 其实也可以以一种更简洁的方法来实现,那就是使用using语句,如下: public void Test() FileManager fs = null; using (fs = new FileManager() Console.WriteLine(fs.ToString(); 我们来看一下编译器生成的IL是什么样的?.method public hidebysig instance void Test() cil managed / 代码大小 45 (0x2d) .maxstack 2 .locals init (0 class ConsoleApp.Example12.FileManager fs, 1 class ConsoleApp.Example12.FileManager CS$3$0000, 2 bool CS$4$0001) IL_0000: nop IL_0001: ldnull IL_0002: stloc.0 IL_0003: newobj instance void ConsoleApp.Example12.FileManager:.ctor() IL_0008: dup IL_0009: stloc.0 IL_000a: stloc.1 .try IL_000b: nop IL_000c: ldloc.0 IL_000d: callvi
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024年纺织品市场动态分析试题及答案
- 国际美术设计师考试知识点回顾试题及答案
- 2024年助理广告师考试知识图谱试题及答案
- 社工比赛面试题及答案
- 2024年纺织品检验员复习计划试题及答案
- 2024年纺织品设计师证书备考中的经验借鉴试题及答案
- 潍坊化学初中试题及答案
- 2024年纺织品设计师的工作愿景考题及答案
- 精雕细琢2024国际商业美术设计师试题及答案
- 体能教练测试题及答案
- 科技安全课件
- 2024年中交分包商培训参考答案
- 给水管道施工方案与水质保障
- 人工智能导论知到智慧树章节测试课后答案2024年秋天津大学
- 高中生物竞赛《普通动物学-两栖纲》单项选择题95题
- 2024年江苏省泰州市公开招聘警务辅助人员(辅警)笔试专项训练题试卷(1)含答案
- 药品经营许可证换证申请表
- 职场沟通:职场沟通与人际关系处理(山东管理学院)知到智慧树章节答案
- 《土地管理信息系统》课件
- 山东师范大学马克思主义基本原理期末复习题
- 五年(2020-2024)高考英语真题分类汇编 专题12 阅读理解七选五解析版
评论
0/150
提交评论