修补类以计算已创建对象的数量

时间:2012-11-04 00:58:36

标签: perl oop testing memory

我有一个Perl库,它在运行期间使用了一些(大约3或4个)类的许多对象。

在测试代码时,我想确保它不是太多(我不是在谈论内存泄漏,我知道如何检查)。为此,我想我可以计算每个使用的对象并检查运行期间测试数据的最大值。然后,我会比较获得的数字,并猜测库应该使用多少个对象。

但是,我在实现这个问题上遇到了问题。我想到了两种可能的方式:

  • 拦截Package::newPackage::DESTROY。但是,这有一点点,在该包中,new并不总是返回一个新对象。有时候,它使用一个预先存在的对象(这些对象被用作不可变量,所以它应该不重要)。因此,我必须跟踪每个单独的对象,看它是否存在。

  • 拦截Package::blessPackage::DESTROY。这应该有效,但似乎有点不正统。

问题是,哪些方式更有可能成功(也许在类似情况下常用),其次,我如何实现第二种方式(我是否必须覆盖Package::bless所有有问题的包或只有基类等。)。

4 个答案:

答案 0 :(得分:2)

存储已查看对象ID的哈希,以确保只计算每个对象一次。您可以使用Hash::Util::FieldHashObject::ID

执行此操作

idhash的优势在于它不会人为地保持对象的活着。当每个对象被销毁时,它的条目将从idhash中删除。它还具有跨线程工作的优点。

package Foo;

use strict;
use warnings;
use v5.10;

use Hash::Util::FieldHash qw(idhash register id);

idhash my %objects;

sub new {
    my $self = bless {}, shift;
    register $self, \%objects;
    $objects{$self} = 1;

    say "Creating ".id $self;

    my $num_objects = keys %objects;
    say "There are now $num_objects alive.";

    return $self;
}

sub DESTROY {
    my $self = shift;

    my $num_objects = keys(%objects) - 1;

    say "Destroying ".id $self;
    say "There are $num_objects left alive.";
}


{
    my $obj1 = Foo->new;            # 1 object
    my $obj2 = Foo->new;            # 2 objects
    {
        my $obj3 = Foo->new;        # 3 objects
    } # 2 objects
    my $obj4 = Foo->new;            # 3 objects
} # 0 objects
__END__
Creating 4303384168
There are now 1 alive.
Creating 4303542768
There are now 2 alive.
Creating 4303545192
There are now 3 alive.
Destroying 4303545192
There are 2 left alive.
Creating 4303638136
There are now 3 alive.
Destroying 4303542768
There are 2 left alive.
Destroying 4303384168
There are 1 left alive.
Destroying 4303638136
There are 0 left alive.

或者,由于创建的每个对象都将被销毁,因此只有在对象被销毁时才计算。

答案 1 :(得分:2)

关于如何拦截祝福(不是Package :: bless,祝福是内置的,而不是某种方法),大多数内置都是可覆盖的(参见http://perldoc.perl.org/perlsub.html#Overriding-Built-in-Functions)。替换的bless函数会执行你的跟踪(如果一个对象加入你的目标类),然后调用CORE :: bless来实际执行祝福。

答案 2 :(得分:2)

尝试这样的事情(未经测试):

my $Package_objects = {};
my $override_new = *Package::new{CODE};
*Package::new = sub {
    my $self = $override_new->(@_);
    # Interpolate $self as string to get "HASH(0x12345)"; save package name
    $Package_objects->{ "$self" } = 'Package';
    return $self;
};
my $override_dest = *Package::DESTROY{CODE};
*Package::DESTROY = sub {
    delete $Package_objects->{ "$_[0]" };
    $override_dest->(@_);
};

这可能是最野蛮的方法,但必须在没有第三方模块的情况下工作;)

答案 3 :(得分:1)

查看

中使用的技巧

Devel-Leak-Object-1.01

我使用ADAMK的代码作为收集各种对象创建/销毁统计数据的基础。