垃圾回收GC:.Net自动内存管理 上(三)终结器
垃圾回收GC:.Net自动内存管理 上(三)终结器
前言
.Net下的GC完全解决了开发者跟踪内存使用以及控制释放内存的窘态。然而,你或午想要理解GC是怎么工作的。此系列文章中将会解释内存资源是怎么被合理分配及管理的,并包含非常详细的内在算法描述。同时,还将讨论GC的内存清理流程及什么时清理,怎么样强制清理。
终结器
public class BaseObj { public BaseObj() { } protected override void Finalize() { // 实现资源清理的代码 // 比如,关闭文件或网络连接 Console.WriteLine("In Finalize."); } }
现在你可以创建一个此对象的实例:BaseObj bo = new BaseObj();
- 可被终结(Finalize)的对象会被提升到GC的更老一代中,这会增大内存压力并阻止对象内存回收即使GC认为此对象为垃圾对象。另外,所有与此对象有直接或间接关系的对象也会被提升。GC中的代以及代的提升在后续文章中会介绍。
- 可被终结(Finalize)的对象需要更长时间去分配。
- 强制GC执行终结(Finalize)方法会明显降低性能。因此,如果有10000个对象实现了Finalize方法,GC必须执行其10000次终结方法,很伤性能。
- 实现终结器的对象可能引用了没有终结器的对象,导致了那些没有终结器的对象的生命周期的延长。实际上,你可能会想把一个类型分成两个不同的类型:没有引用任何其它对象的带终结器的轻量级类型和引用了其它对象而不带终结器的类型。
- 你无法控制终结器方法的执行时间。因此,它可能会占有一定的资源不释放直到GC的下次回收。
- 当一个程序终止时,一些对象始终可以被访问到并且不会执行其终结器。比如,后台线程使用的对象或者程序终止(或程序域卸载)过程中创建的对象。另外,默认地,为了程序能够终止迅速,当一个程序终止时不会调用无法被访问到的对象的终结器。当然,所有操作系统资源都会被回收利用,但是在托管堆中的对象是不能够被恰当清理的。如果你想改变这个默认行为,你可以调用System.GC的RequestFinalizeOnShutdown方法。不过,你一定要小心地使用此方法,因为调用此方法意味着你的这个类型正在控制整个应用程序的策略。
- 程序运行时无法保证终节器的执行顺序。比如,一个对象包含一个指针指向一个内部对象,GC检到这两个对象都是垃圾。更进一步说,内部对象的终结器先被调用。现在,外部对象的终结器能够访问到内部对象并且调用其方法,但是内部对象已经被终结了。此时,结果是无法预知的。由于这个原因,强烈推荐终结器不要访问任何内部成员对象。
public class BaseObj {
public BaseObj() {
}
protected override void Finalize() {
Console.WriteLine("In Finalize.");
base.Finalize(); // 调用基类终结器
}
}
class MyObject {
~MyObject() {
//其它代码
}
}
causes the compiler to generate this code: class MyObject {
protected override void Finalize() {
//其它代码
base.Finalize();
}
}
这和C++析构器有些像,但是记住C#不支持析构器。
终结器内部
下图中堆中存放着几个对象。一些对象可以被程序根访问到,一些不能。当对象C,E,F,I和J被创建,系统检测到这些对象实现了终结器,同时在终结器队列里添加了指向这些对象的指针。
总结
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。