• 第九节:对象复活


    前面“终结操作解密”讲过,需要终结一个对象被认为死亡时,垃圾回收器会强制对象重生,使它的Finalize方法得以调用。Finalize方法调用之后,对象才真正死亡。总之,需要终结的一个对象会经历死亡、重生、再死亡的“三部曲”。一个死亡的对象重生的过程称为复活。

    准备调用对象的Finalize方法,这是复活的一种形式。垃圾回收器将一个对象引用放入freachable队列时,对象就从根可达,得以复活。这是必须的,因为只有这样,Finalize方法中的代码才能访问对象的字段。最终,对象的Finalize方法返回,不再有任何根指向对象(因为对象已从freachable队列中移除),对象宣布真正死亡。

    但是,如下代码所示,如果Finalize方法在执行时将指向这个对象的指针放到一个静态字段中,又会怎样?

    Calss  SomeType

    {

          ~SomeType()

    {

    Program. s_objHolder=this;

    }

    }

    Static class program

    {

     Public static object  s_objHolder;

    }

    在本例中,当SomeType对象的Finalize方法被调用时,对该对象的引用被放入了一个根,使对象从应用程序的代码中可达。对象现在就复活了,垃圾回收期不再认为它是垃圾。应用程序可自由使用该对象。但必须记住的是,该对象曾被终结,所以使用它可能造成无法预测的后果,另外还要注意,如果SomeType的一些字段引用了其他对象,所有的对象都会复活,因为他们都从应用程序 根可达。但请注意,在这些对象中,一部分对象的Finalize方法可能已经调用过。

    复活一般不是一件好事,应避免写代码来使用CLR这个功能。只有在应用程序的体系结构要求反复使用同一个对象时,复活才有用处。在这种情况下,当对象使用完毕时,会发生垃圾回收。在对象的Finalize方法中,它将它的this指针赋给另一个根,阻止对象死亡。但是,你想告诉垃圾回收器在下一次使用之后,再次调用Finalize方法,为此,GC类提供了一个ReRegisterForFinalize的静态方法,该方法只有一个参数,也就是对象引用,

    Calss  SomeType

    {

          ~SomeType()

    {

    Program. s_objHolder=this;

    GC. ReRegisterForFinalize(this);

    }

    }

    Finalize方法被调用时,它让一个根引用对象,从而时对象复活。然后,Finalize方法调用ReRegisterForFinalize,后者将指定对象的指针添加到终结者列表末尾。当垃圾回收器判断这个对象不可达时(未来在某个时刻,当静态字段为null),他会将对象的指针从终结者列表移到freachable队列,造成对象的Finalize方法被再次调用。记住,复活一个对象,将复活该对象引用的所有对象,可能需要为所有这些对象调用ReRegisterForFinalize,但大多数情况下都不可能是这样做,因为无权访问其他对象的私有字段。

    这个例子演示了如何创建一个不断复活,永远死不了的对象,但是一般都不希望对象有这样的行为。更常见的做法实在Finalize方法中条件性的设置一个根来引用对象。

    注意 :要保证每一次复活时,都的调用ReRegisterForFinalize方法一次,否则对象的Finalize方法会被调用多次,这是因为每调用一次ReRegisterForFinalize方法,都会在终结列表中追加一条记录项。对象被判断为垃圾后,所有这些记录项都被移到freachable队列中,导致对象的Finalize方法被多次调用。

  • 相关阅读:
    内网其他服务器节点连接Mysql数据库很慢的解决方案
    MongoDB分片技术原理和高可用集群配置方案
    Hive事务原理和Datax同步事务表问题解决
    Mysql使用存储过程创建测试数据
    Hive的原生部署方式
    ByteArray的操作总结(复制、打印、位运算)
    句柄
    C# 使用指针将不同值类型赋值到字节数组中
    对象、字节流转换
    ASP.NET Core学习日志1
  • 原文地址:https://www.cnblogs.com/bingbinggui/p/4445191.html
Copyright © 2020-2023  润新知