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::Util
的weaken
功能'弱化’的引用...但是如果我削弱了引用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
仍然存在并且需要使用来自父对象的一些数据,这将导致问题,因为子对象现在将持有指向父对象的无效指针.
my $x = { };
+============+ +==========+
$x -----> [ Reference ------->[ Hash ]
[ REFCNT=1 | [ REFCNT=1 ]
+============+ [ ]
+==========+
Run Code Online (Sandbox Code Playgroud)my $y = $x;
+============+ +==========+
$x -----> [ Reference ------->[ Hash ]
[ REFCNT=1 | +-->[ REFCNT=2 ]
+============+ | [ ]
| +==========+
+============+ |
$y -----> [ Reference ----+
[ REFCNT=1 |
+============+
Run Code Online (Sandbox Code Playgroud)weaken($y);
+============+ +==========+
$x -----> [ Reference ------->[ Hash ]
[ REFCNT=1 | +-->[ REFCNT=1 ]
+============+ | [ BACKREFS ---+
| +==========+ |
+============+ | |
$y -----> [ Weak Ref -----+ |
+--> [ REFCNT=1 | |
| +============+ |
+--------------------------------------+
Run Code Online (Sandbox Code Playgroud)
除了WEAKREF
在引用中设置标志外,还降低了引用变量的引用计数,并创建了反向引用.
如果$y
超出范围,第二个引用的REFCNT将降为零,这将释放引用.这通常会丢弃散列的引用计数,除了释放的引用是弱引用.因此,它只会将自己从反向引用列表中删除.
+============+ +==========+
$x -----> [ Reference ------->[ Hash ]
[ REFCNT=1 | [ REFCNT=1 ]
+============+ [ ]
+==========+
Run Code Online (Sandbox Code Playgroud)
如果$x
超出范围,第一个引用的REFCNT将降为零,这将释放引用,这将使哈希的引用计数降为零,这将导致哈希被释放.作为其中的一部分,每个反向引用的变量将是undef.
+============+
$y -----> [ Undefined |
[ REFCNT=1 |
+============+
Run Code Online (Sandbox Code Playgroud)
此时print("$y->{foo}\n");
将会出现错误(退出并显示错误消息,而不是违反分段),您可以通过检查是否$y
先定义来避免.
它不会是一个"无效的参考",它会undef
.当对某事物的最后一个非弱引用超出范围(或被削弱)时,那些对该事物的所有弱引用都会变为undef
.
但是,是的,如果父母对其子女只有弱引用,并且孩子对父母只有弱引用,那么如果唯一的强引用$parent
超出范围,那么你仍然有其他引用的任何孩子现在都会undef
在他们的parent
领域.