覆盖对象时的Perl内存管理

时间:2015-08-12 17:21:02

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

我的问题是关于Perl如何在内部管理对象的数据。

在Perl中创建对象时,新子例程通常会返回对受祝福对象的引用。

以下面的代码为例:

# Create a new object
my $object = Object->new(%data1);

# Create a new object with the same variable
$object = Object->new(%data2);

从第一次致电new开始,我们创建了$object,引用了一些有福的%data1

  

视觉表现:

     

“\”表示引用。

$object ════> \{bless %data1}
  

在内存中看起来如下:

     

“&”象征着一个地址

MEMORY:
----------------------------------
&{bless %data1} ════> bless %data1

然后第二次调用new时,$object的值会更改为引用其他一些有福的%data2

  

视觉表现:

$object ══/ /══> \{bless %data1}  # The connection to %data1 is broken
   ║
   ╚═══════════> \{bless %data2}
  

现在内存看起来像这样:

MEMORY:
----------------------------------
&{bless %data1} ════> bless %data1
&{bless %data2} ════> bless %data2

现在问题是$object不再存储引用\{bless %data1},地址&{bless %data1},并且存储在此地址的任何数据都将永久丢失。没有办法从脚本中访问存储在该位置的数据。

我的问题是。 。 。 Perl足够聪明,一旦永久丢失对此数据的引用,就会删除存储在&{bless %data1}中的数据,或者Perl会将这些数据保留在内存中可能导致内存泄漏吗?

4 个答案:

答案 0 :(得分:6)

鉴于

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        ]
                             [          ]   +==========+
                             +==========+

(箭头代表指针。)

Perl使用引用计数来确定何时释放变量。作为赋值的一部分,名称(引用)当前引用的变量的引用计数将递减,从而使其被释放 [1] 。这将删除散列的引用计数,导致它被释放 [1] 。这将删除值的引用计数,导致它们被释放 [1]

在Perl中,当你有循环引用时会出现内存泄漏。

{
   my $parent = Node->new();
   my $child = Node->new();
   $parent->{children} = [ $child ];
   $child->{parent} = $parent;
}

退出街区之前,你有

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

存在块之后,你有

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

内存没有被释放,因为所有内容仍然被引用,因为有一个引用周期。由于您无法访问此结构(没有变量名称引用其中的任何内容),因此它是内存泄漏。

  1. 假设没有其他任何引用(指向)那些变量。

答案 1 :(得分:4)

你误解了参数传递的工作方式。 $object成为新创建的引用,其内容可能会受到传递给构造函数new的数据的影响,但它不会引用哈希值{{1} }或%data1自己为%data2仅提供这些哈希的键/值内容

问题的底线似乎是Perl是否足够聪明,可以在不再使用时解除分配对象,答案是,是的,是的

Perl保留对每个数据项的引用计数,如果它已经降到零(即不再有任何方法可以达到该数据),那么数据被认为可以重用

Perl可能导致内存泄漏的唯一情况是数据结构包含对自身的引用。在这种情况下,外部引用的数量可能会降为零,但数据不会被自己的引用删除,从而使计数不会下降到零

避免包变量也更安全,并且只使用用new声明的词法变量。当词汇变量超出范围时,它们将自动销毁,因此减少了它们可能包含的任何引用的计数。使用my声明的包变量将在进程的整个生命周期内存在,并且不会触发此安全措施

如果您再解释一下为什么需要这些信息,那么我相信您会得到更好的答案

答案 2 :(得分:3)

Perl使用一种称为引用计数的方法 - 它计算引用变量的次数。它将数据保存在内存中,直到引用计数降至零。

在您的示例中,一旦重新分配$object,创建的第一个对象将自动消失。但是有一点需要注意 - 如果对象中并且new进程创建了循环引用,则不会发生这种情况。您可以在weaken中使用Scalar::Util来处理此问题。

您可以通过创建DESTROY方法来观察它,该方法在对象被“释放”时调用。

答案 3 :(得分:0)

有引用计数垃圾收集。我的代码中没有看到任何会绊倒的内容。即使有,Scalar :: Util还有其他选项减弱。