使用Scalar :: Util的弱化会导致无效的引用问题吗?

时间:2015-08-14 15:03:20

标签: perl oop memory-management reference cyclic-reference

有关背景信息,请参阅此related question

注意:当我说“无效引用”时,我指的是指向无数据的引用。

假设我们有以下包含循环引用的数据结构:

       +-----------------------------------------------------+
       |                                                     |
       +-->+============+    +==========+                    |
           [ Reference ----->[ Blessed  ]                    |
$parent -->+============+    [ Hash     ]                    |
                             [          ]   +==========+     |
                             [ children --->[ Array    ]     |
                             [          ]   [          ]     |
                             +==========+   [ 0: ---------+  |
                                            [          ]  |  |
                                            +==========+  |  |
                                                          |  |
       +--------------------------------------------------+  |
       |                                                     |
       +-->+============+    +==========+                    |
           [ Reference ----->[ Blessed  ]                    |
$child --->+============+    [ Hash     ]                    |
                             [          ]                    |
                             [ parent: ----------------------+
                             [          ]
                             +==========+

我知道我可以使用Scalar::Utilweaken函数来“削弱”引用。 。 。但是如果我从parent->child削弱参考并且从child->parent削弱参考,然后$child$parent超出范围,而不是另一个,会发生什么?< / p>

示例: $parent超出范围,因此引用已消失。

       +-----------------------------------------------------+
       |                                                     |
       +-->+============+    +==========+                    |
           [ Reference ----->[ Blessed  ]                    |
           +============+    [ Hash     ]                    |
                             [          ]   +==========+     |
                             [ children --->[ Array    ]     |
                             [          ]   [          ]     |
                             +==========+   [ 0: ---------+  |
                                            [          ]  |  |
                                            +==========+  |  |
                                                          |  |
                 would this break the link? ------------> X  X
                                                          |  |
       +--------------------------------------------------+  |
       |                                                     |
       +-->+============+    +==========+                    |
           [ Reference ----->[ Blessed  ]                    |
$child --->+============+    [ Hash     ]                    |
                             [          ]                    |
                             [ parent: ----------------------+ <--- would this parent object pointer now be invalid?
                             [          ]
                             +==========+

如果我这样做,然后“父”超出范围,那么 是否会从内存中删除父对象,因为该对象的Perl内部引用计数为0? < / strong>我问这个,因为如果$child仍然存在并且需要使用来自父对象的一些数据,这会导致问题,因为子对象现在会持有指向父对象的无效指针。

1 个答案:

答案 0 :(得分:7)

  1. my $x = { };

              +============+      +==========+
    $x -----> [ Reference ------->[ Hash     ]
              [ REFCNT=1   |      [ REFCNT=1 ]
              +============+      [          ]
                                  +==========+
    
  2. my $y = $x;

              +============+      +==========+
    $x -----> [ Reference ------->[ Hash     ]
              [ REFCNT=1   |  +-->[ REFCNT=2 ]
              +============+  |   [          ]
                              |   +==========+
              +============+  |
    $y -----> [ Reference ----+
              [ REFCNT=1   |
              +============+
    
  3. weaken($y);

              +============+      +==========+
    $x -----> [ Reference ------->[ Hash     ]
              [ REFCNT=1   |  +-->[ REFCNT=1 ]
              +============+  |   [ BACKREFS ---+
                              |   +==========+  |
              +============+  |                 |
    $y -----> [ Weak Ref -----+                 |
         +--> [ REFCNT=1   |                    |
         |    +============+                    |
         +--------------------------------------+
    

    除了在引用中设置WEAKREF标志外,引用变量的引用计数已降低,并且已创建反向引用。

  4. 场景1

    如果$y超出范围,则第二个引用的REFCNT将降为零,这将释放引用。这通常会丢弃散列的引用计数,除了释放的引用是弱引用。因此,它只会将自己从反向引用列表中删除。

              +============+      +==========+
    $x -----> [ Reference ------->[ Hash     ]
              [ REFCNT=1   |      [ REFCNT=1 ]
              +============+      [          ]
                                  +==========+
    

    场景2

    如果$x超出范围,第一个引用的REFCNT将降为零,这将释放引用,这将使哈希的引用计数降为零,这将导致哈希被释放。作为其中的一部分,每个反向引用的变量都将成为undef。

              +============+
    $y -----> [ Undefined  |
              [ REFCNT=1   |
              +============+
    

    此时print("$y->{foo}\n");将会嘶哑(退出并显示错误消息,而不是分段违规),您可以通过检查是否先定义$y来避免这种情况。