覆盖对象时的Perl内存管理
我的问题是Perl如何在内部管理对象的数据 在Perl中创建对象时,新的子例程通常会返回对对象的引用 以下面的代码为例:覆盖对象时的Perl内存管理,perl,oop,memory-management,memory-leaks,reference,Perl,Oop,Memory Management,Memory Leaks,Reference,我的问题是Perl如何在内部管理对象的数据 在Perl中创建对象时,新的子例程通常会返回对对象的引用 以下面的代码为例: 从第一次调用new开始,我们创建了一个$object,它引用了一些受祝福的%data1 # Create a new object my $object = Object->new(%data1); # Create a new object with the same variable $object = Object->new(%data2); 视觉表现
从第一次调用
new
开始,我们创建了一个$object
,它引用了一些受祝福的%data1
# Create a new object
my $object = Object->new(%data1);
# Create a new object with the same variable
$object = Object->new(%data2);
视觉表现:
“\”表示引用
这将在内存中显示如下:
“&”代表一个地址
然后在第二次调用
new
时,$object
的值被更改为引用一些其他的%data2
# Create a new object
my $object = Object->new(%data1);
# Create a new object with the same variable
$object = Object->new(%data2);
视觉表现:
现在,内存将如下所示:
现在的问题是,
$object
不再存储引用\{bless%data1}
、地址&{bless%data1}
,并且存储在此地址的任何数据都将永远丢失。无法再从脚本访问存储在该位置的数据
我的问题是。一旦对该数据的引用永久丢失,Perl是否足够聪明,可以删除存储在
&{bless%data1}
中的数据,或者Perl是否会将该数据保留在内存中,从而可能导致内存泄漏?存在引用计数垃圾收集。“我没有在你的代码中看到任何会出错的东西,”他说。即使有,Scalar::Util和其他选项中也有削弱。您误解了参数传递的工作方式$object
成为一个新创建的引用,其内容可能会受到传递给构造函数的数据的影响new
,但它不会引用散列%data1
或%data2
本身,因为new
只提供这些散列的键/值内容
您的问题的底线似乎是Perl是否足够聪明,可以在不再使用对象时释放对象,答案是,是的
Perl保留对每个数据项的引用计数,如果该值降至零(即不再有任何方法可以访问该数据),则认为该数据可供重用
Perl导致内存泄漏的唯一情况是数据结构包含对自身的引用。在这种情况下,外部引用的数量可能会降至零,但数据本身不会被自己的引用删除,从而使计数不会降至零
避免使用包变量,只使用用my
声明的词法变量也更安全。词法变量将在超出范围时自动销毁,从而减少它们可能包含的任何引用的数量。用our
声明的包变量将在进程的另一个生命周期内存在,并且不会触发此保护
如果您进一步解释一下为什么需要这些信息,那么我相信您会得到更好的答案Perl使用了一种称为引用计数的方法—它计算变量被引用的次数。它将数据保存在内存中,直到引用计数降至零 在您的示例中,一旦重新指定
$object
,创建的第一个对象将自动消失。但是有一个警告-如果在对象和new
过程中创建循环引用,则不会发生这种情况。您可以在Scalar::Util
中使用delever
来处理此问题
您可以通过创建DESTROY
方法来观察它,该方法在对象被“释放”时调用 给定
package Object {
sub new { my $class = shift; bless({ @_ }, $class) }
}
my $object = Object->new( a => 1, b => 2 );
在第二次作业之前,你必须
+============+ +==========+
$object -->[ Reference ---->[ Blessed ]
+============+ [ Hash ]
[ ] +==========+
[ a: --------->[ 1 ]
[ ] +==========+
[ ]
[ ] +==========+
[ b: --------->[ 2 ]
[ ] +==========+
+==========+
$parent +----------------------------------------------------+
| | |
| +============+ +-->+==========+ |
+-->[ Reference -------->[ Blessed ] |
+============+ [ Hash ] |
[ ] +==========+ |
[ children --->[ Array ] |
[ ] [ ] +============+ |
+==========+ [ 0: --------->[ Reference ----+ |
[ ] +============+ | |
+==========+ | |
| |
$child +-------------------------------------------------+ |
| | |
| +============+ +-->+==========+ |
+-->[ Reference -------->[ Blessed ] |
+============+ [ Hash ] |
[ ] +============+ |
[ parent: ---->[ Reference ----------------------+
[ ] +============+
+==========+
+----------------------------------------------------+
| |
+-->+==========+ |
[ Blessed ] |
[ Hash ] |
[ ] +==========+ |
[ children --->[ Array ] |
[ ] [ ] +============+ |
+==========+ [ 0: --------->[ Reference ----+ |
[ ] +============+ | |
+==========+ | |
| |
+-------------------------------------------------+ |
| |
+-->+==========+ |
[ Blessed ] |
[ Hash ] |
[ ] +============+ |
[ parent: ---->[ Reference ----------------------+
[ ] +============+
+==========+
(箭头表示指针。)
Perl使用引用计数来确定何时释放变量。作为赋值的一部分,当前由名称(引用)引用的变量的引用计数将减少,从而使其被释放[1]。这将删除散列的引用计数,导致散列被释放[1]。这将删除这些值的引用计数,从而释放它们[1]
在Perl中,循环引用会导致内存泄漏
{
my $parent = Node->new();
my $child = Node->new();
$parent->{children} = [ $child ];
$child->{parent} = $parent;
}
在离开街区之前,你必须
+============+ +==========+
$object -->[ Reference ---->[ Blessed ]
+============+ [ Hash ]
[ ] +==========+
[ a: --------->[ 1 ]
[ ] +==========+
[ ]
[ ] +==========+
[ b: --------->[ 2 ]
[ ] +==========+
+==========+
$parent +----------------------------------------------------+
| | |
| +============+ +-->+==========+ |
+-->[ Reference -------->[ Blessed ] |
+============+ [ Hash ] |
[ ] +==========+ |
[ children --->[ Array ] |
[ ] [ ] +============+ |
+==========+ [ 0: --------->[ Reference ----+ |
[ ] +============+ | |
+==========+ | |
| |
$child +-------------------------------------------------+ |
| | |
| +============+ +-->+==========+ |
+-->[ Reference -------->[ Blessed ] |
+============+ [ Hash ] |
[ ] +============+ |
[ parent: ---->[ Reference ----------------------+
[ ] +============+
+==========+
+----------------------------------------------------+
| |
+-->+==========+ |
[ Blessed ] |
[ Hash ] |
[ ] +==========+ |
[ children --->[ Array ] |
[ ] [ ] +============+ |
+==========+ [ 0: --------->[ Reference ----+ |
[ ] +============+ | |
+==========+ | |
| |
+-------------------------------------------------+ |
| |
+-->+==========+ |
[ Blessed ] |
[ Hash ] |
[ ] +============+ |
[ parent: ---->[ Reference ----------------------+
[ ] +============+
+==========+
在存在块之后,您就有了
+============+ +==========+
$object -->[ Reference ---->[ Blessed ]
+============+ [ Hash ]
[ ] +==========+
[ a: --------->[ 1 ]
[ ] +==========+
[ ]
[ ] +==========+
[ b: --------->[ 2 ]
[ ] +==========+
+==========+
$parent +----------------------------------------------------+
| | |
| +============+ +-->+==========+ |
+-->[ Reference -------->[ Blessed ] |
+============+ [ Hash ] |
[ ] +==========+ |
[ children --->[ Array ] |
[ ] [ ] +============+ |
+==========+ [ 0: --------->[ Reference ----+ |
[ ] +============+ | |
+==========+ | |
| |
$child +-------------------------------------------------+ |
| | |
| +============+ +-->+==========+ |
+-->[ Reference -------->[ Blessed ] |
+============+ [ Hash ] |
[ ] +============+ |
[ parent: ---->[ Reference ----------------------+
[ ] +============+
+==========+
+----------------------------------------------------+
| |
+-->+==========+ |
[ Blessed ] |
[ Hash ] |
[ ] +==========+ |
[ children --->[ Array ] |
[ ] [ ] +============+ |
+==========+ [ 0: --------->[ Reference ----+ |
[ ] +============+ | |
+==========+ | |
| |
+-------------------------------------------------+ |
| |
+-->+==========+ |
[ Blessed ] |
[ Hash ] |
[ ] +============+ |
[ parent: ---->[ Reference ----------------------+
[ ] +============+
+==========+
内存未被释放,因为存在引用循环,所以所有内容仍在被引用。由于您无法访问此结构(没有变量名引用其中的任何内容),因此这是内存泄漏
你能详细说明一下吗?您似乎在说这不会是一个问题,但具体来说,Perl如何以一种不会发生这种情况的方式处理内存?我需要这些信息,因为我有创建对象并将其存储在变量中的代码,然后如果满足某些条件,它将使用相同的变量并创建一个新对象。这与问题中描述的情况基本相同。@tjwrona1992:好吧,但你和成千上万不需要问这个问题的程序员处于相同的情况。你遇到内存泄漏了吗?在我使用它的方式中,没有对自身的引用,所以我认为我是安全的。谢谢@Borodin@tjwrona1992:避免使用包变量,只使用用
my
声明的词法变量也更安全。词法变量将在超出范围时自动销毁,从而减少它们可能包含的任何引用的数量。用our
声明的包变量将在进程的另一个生命周期内存在,并且不会触发此安全保护。我知道,我没有使用任何包变量。我只是想知道,在引用丢失(即使在词汇上下文中也可能发生)后,对象是否会保留在内存中。如果我