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

tjw*_*992 3 oop perl memory-management reference cyclic-reference

有关背景信息,请参阅此相关问题.

注意:当我说"无效引用"时,我指的是指向无数据的引用.


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

       +-----------------------------------------------------+
       |                                                     |
       +-->+============+    +==========+                    |
           [ Reference ----->[ Blessed  ]                    |
$parent -->+============+    [ Hash     ]                    |
                             [          ]   +==========+     |
                             [ children --->[ Array    ]     |
                             [          ]   [          ]     |
                             +==========+   [ 0: ---------+  |
                                            [          ]  |  |
                                            +==========+  |  |
                                                          |  |
       +--------------------------------------------------+  |
       |                                                     |
       +-->+============+    +==========+                    |
           [ Reference ----->[ Blessed  ]                    |
$child --->+============+    [ Hash     ]                    |
                             [          ]                    |
                             [ parent: ----------------------+
                             [          ]
                             +==========+
Run Code Online (Sandbox Code Playgroud)

我明白,我可以使用Scalar::Utilweaken功能'弱化’的引用...但是如果我削弱了引用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?
                             [          ]
                             +==========+
Run Code Online (Sandbox Code Playgroud)

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

ike*_*ami 7

  1. my $x = { };

              +============+      +==========+
    $x -----> [ Reference ------->[ Hash     ]
              [ REFCNT=1   |      [ REFCNT=1 ]
              +============+      [          ]
                                  +==========+
    
    Run Code Online (Sandbox Code Playgroud)
  2. my $y = $x;

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

              +============+      +==========+
    $x -----> [ Reference ------->[ Hash     ]
              [ REFCNT=1   |  +-->[ REFCNT=1 ]
              +============+  |   [ BACKREFS ---+
                              |   +==========+  |
              +============+  |                 |
    $y -----> [ Weak Ref -----+                 |
         +--> [ REFCNT=1   |                    |
         |    +============+                    |
         +--------------------------------------+
    
    Run Code Online (Sandbox Code Playgroud)

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

场景1

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

          +============+      +==========+
$x -----> [ Reference ------->[ Hash     ]
          [ REFCNT=1   |      [ REFCNT=1 ]
          +============+      [          ]
                              +==========+
Run Code Online (Sandbox Code Playgroud)

情景2

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

          +============+
$y -----> [ Undefined  |
          [ REFCNT=1   |
          +============+
Run Code Online (Sandbox Code Playgroud)

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


cjm*_*cjm 5

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

但是,是的,如果父母对其子女只有弱引用,并且孩子对父母只有弱引用,那么如果唯一的强引用$parent超出范围,那么你仍然有其他引用的任何孩子现在都会undef在他们的parent领域.

  • 这取决于你所拥有的确切结构以及你期望它的使用方式.我认为从孩子到父母的弱参考是最常见的,但可能存在另一个方向会更好的情况. (2认同)