3

请参阅此相关问题以获取一些背景信息。

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


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

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

我知道我可以使用Scalar::Util'sweaken函数来“弱化”引用。. . 但是,如果我削弱了来自的引用parent->child并削弱了来自的引用child->parent,然后其中一个$child$parent超出范围,但不是另一个,会发生什么?

示例: $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 而从内存中删除父对象?我问这个,因为如果$child仍然存在并且需要使用来自父对象的一些数据,这会导致问题,因为子对象现在将持有指向父对象的无效指针。

4

2 回答 2

8
  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在引用中设置标志之外,被引用变量的引用计数被降低,并且创建了反向引用。

方案 1

如果$y超出范围,第二个引用的 REFCNT 将降为零,这将释放该引用。这通常会降低哈希的引用计数,除非释放的引用是弱引用。所以它只会将自己从反向引用列表中删除。

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

方案 2

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

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

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

于 2015-08-14T15:21:38.887 回答
5

它不会是“无效引用”,而是undef. 当对某事物的最后一个非弱引用超出范围(或被削弱)时,对该事物的所有弱引用都变为undef.

但是,是的,如果父级对其子级只有弱引用,而子级对其父级只有弱引用,那么如果唯一的强引用$parent超出范围,那么您仍然有其他引用的任何子级现在都将undef在它们的parent场地。

于 2015-08-14T15:13:12.540 回答