• [C#]C#学习笔记垃圾回收机制


    C#学习笔记-垃圾回收机制

    罗朝辉(http://www.cnblogs.com/kesalin/)

    《C#与.NET高级程序设计》读书笔记

    1,C#的垃圾回收机制

    C#的垃圾回收机制不是基于引用计数的,而是基于对象是否可到达。该机制的运作过程是:CLR 会建立一个对象图,代表堆上可达的每一个对象,如果在一次垃圾回收过程中,某个对象在该对象图上没有root(即没有任何其他对象依赖于它),则对象是不可达对象,会被标记为垃圾,从而会被终结,从内存中清除。 微软的回收算法使用对象代,用于终结对象的辅助线程和专门承载大对象的托管堆进行优化以提高垃圾回收机制的效率。

    2,终结过程

    Finalize() 的作用是保证.NET对象能在垃圾回收时清除非托管资源。如果创建了一个不使用非托管实体的类型,终结是没有用的。事实上,尽可能在设计时避免提供Finalize()以提高效率,因为终结是需要花费时间的。当在托管堆上分配对象时,运行库自动确定该对象是否提供一个自定义的Finalize()方。如果是这样的话,该对象就被标记为可终结的,同时一个指向该对象的指针被保存至名为终结队列的内部队列中。终结队列是一个由垃圾回收器维护的表,它指向每一个在从堆上删除之前必须被终结的对象。

    当垃圾回收器确定需要从内存中释放一个对象时,它会检查终结队列中的每一项,并将对象从堆上复制到另一个称作终结可达表的托管结构上。此时,下一个垃圾回收时将产生另一个线程,为每一个可达表中的对象调用Finalize()方法。因此,为了真正终结一个对象,至少要进行两次垃圾回收。

    总而言之,尽管对象的终结能够保证对象可以清除非托管的资源,但它本质上仍然是非确定的,而且由于额外的幕后处理,速度会变得相当慢。为了尽可能快地释放非托管资源,我们引入了 IDisposable 接口,该接口定义了一个名为 Dispose() 的方法,该方法假设当对象的用户不再使用该对象时,会这个对象引用离开作用域之前手工地调用 Dispose()。这样对象可以执行任何必要的非托管资源的清除,而不会再有对象放在终结队列上导致的性能损失,也不必等到垃圾回收触发类的终结逻辑。

    Finalize()只适用于类类型,而 IDisposable 接口对结构和类类型均适用。注意,如果对象支持 IDisposable 接口,那么总是要对任何直接创建的对象调用 Dispose(),因为如果类设计者选择实现该接口,说明该类需要手动执行清理工作。注意:基类库中的许多类型实现了该接口,并提供了 Dispose() 方法的别名,如 System.IO.FileSteam类 Close()。我们可以不管别名,只调用 Dispose() 总是正确的。

    3,可重用 using 关键字来简化在 try/finally 块中手动调用 Dispose() 方法的编写。using 语法保证当使用支持 IDisposable接口的.NET类型的对象在退出using块时,该对象会自动调用Dispose()方法。

    4,可终结类型是重写了System.Object.Finalize()虚方法(在析构函数中编写清除代码)以在回收垃圾时清除非托管资源的类。而可处置对象是实现了IDisposable接口的类或结构,对象用户将在IDisposable接口被实行后调用它。我们可以将这两种方式结合,如果对象用户调用了Dispose(),则可以通过调用GC.SuppressFinalize()通知垃圾回收器跳过终结过程;如果对象用户忘记调用Dispose(),对象最终也将被终结并有机会释放内部资源。对象的内部非托管资源总会用其中一种方式被释放掉。

  • 相关阅读:
    C语言函数sscanf()的用法(转)
    GDB基本命令(整合)(转)
    单元命中率与字节命中率
    rpm安装找不到.so库文件(linux动态库连接的相关知识)(转)
    Linux下的tar压缩解压缩命令详解(转)
    Linux系统如何查看版本信息
    Linux /bin, /sbin, /usr/bin, /usr/sbin 区别(转)
    rsync问题-connection refused(111)、Unknown module
    转: 浅析Fusion-IO和Intel SSD
    转: 从0到1的电商架构应该怎么做?
  • 原文地址:https://www.cnblogs.com/kesalin/p/csharp_gc.html
Copyright © 2020-2023  润新知