除了其他帖子 cmets,即使您确实获得了唯一的对象标识符,如果您没有在哈希键以外的其他位置创建对该对象的引用,则该对象可能会超出范围,得到垃圾收集起来,变得无法访问。
看看这个代码示例及其产生的结果:
use strict;
use warnings;
$|++;
{
package X;
use Moose;
has side => ( isa => 'Str', is => 'rw', required => 1 );
has foo => ( isa => 'Int', is => 'rw', required => 1 );
sub DEMOLISH {
my ( $self ) = @_ ;
printf "Destroyed %i ( %s )\n" , $self->foo, $self->side;
}
__PACKAGE__->meta->make_immutable;
}
{
package Y;
my $hash = {};
for ( 1 .. 5 ){
print "Creating $_ \n";
my $k = X->new( foo => $_ , side => 'key' );
my $v = X->new( foo => $_, side => 'value' );
$hash->{$k} = $v;
print "Created $_ at $k \n";
}
for ( keys %$hash ){
print "Emptying Hash slowly, doing key $_ \n";
delete $hash->{$_};
}
}
输出:
Creating 1
Created 1 at X=HASH(0x2597d08)
Destroyed 1 ( key )
Creating 2
Created 2 at X=HASH(0x2fca7c0)
Destroyed 2 ( key )
Creating 3
Created 3 at X=HASH(0x2fca808)
Destroyed 3 ( key )
Creating 4
Destroyed 1 ( value )
Created 4 at X=HASH(0x2597d08)
Destroyed 4 ( key )
Creating 5
Created 5 at X=HASH(0x2597d68)
Destroyed 5 ( key )
Emptying Hash slowly, doing key X=HASH(0x2597d68)
Destroyed 5 ( value )
Emptying Hash slowly, doing key X=HASH(0x2597d08)
Destroyed 4 ( value )
Emptying Hash slowly, doing key X=HASH(0x2fca808)
Destroyed 3 ( value )
Emptying Hash slowly, doing key X=HASH(0x2fca7c0)
Destroyed 2 ( value )
您会看到每个关键对象在循环结束时都被 GC 处理,因为不再有任何对它的引用。
而且你会看到一个额外的有趣的事情,我们为“4”生成的键对象使用了与“1”相同的内存地址,所以当我们在哈希中替换它的值时,这个值也被 GC'd 了。 :/
解决这个问题相当简单,这里有一种方法:
use strict;
use warnings;
$|++;
{
package X;
use Moose;
use Data::UUID;
my $ug = Data::UUID->new();
has side => ( isa => 'Str', is => 'rw', required => 1 );
has foo => ( isa => 'Int', is => 'rw', required => 1 );
has uuid => ( isa => 'Str', is => 'rw', required => 1 , builder => '_build_uuid' );
sub _build_uuid {
return $ug->create_str();
}
sub DEMOLISH {
my ( $self ) = @_ ;
printf "Destroyed %i ( %s , %s )\n" , $self->foo, $self->side, $self->uuid;
}
__PACKAGE__->meta->make_immutable;
}
{
package Y;
my $hash = {};
my $keys = {};
for ( 1 .. 5 ){
print "Creating $_ \n";
my $k = X->new( foo => $_ , side => 'key' );
my $v = X->new( foo => $_, side => 'value' );
$keys->{$k->uuid} = $k;
$hash->{$k->uuid} = $v;
print "Created $_ at $k \n";
}
for ( sort keys %$hash ){
print "Emptying Hash slowly, doing key $_ \n";
delete $hash->{$_};
delete $keys->{$_};
}
}
输出:
Creating 1
Created 1 at X=HASH(0x2a12b58)
Creating 2
Created 2 at X=HASH(0x2a0d068)
Creating 3
Created 3 at X=HASH(0x2a28960)
Creating 4
Created 4 at X=HASH(0x2a28b28)
Creating 5
Created 5 at X=HASH(0x2a28c18)
Emptying Hash slowly, doing key ADD9C702-E254-11DF-A4A3-F48B02F52B7F
Destroyed 1 ( value , ADD9CA18-E254-11DF-A4A3-F48B02F52B7F )
Destroyed 1 ( key , ADD9C702-E254-11DF-A4A3-F48B02F52B7F )
Emptying Hash slowly, doing key ADD9CBD0-E254-11DF-A4A3-F48B02F52B7F
Destroyed 2 ( value , ADD9CCD4-E254-11DF-A4A3-F48B02F52B7F )
Destroyed 2 ( key , ADD9CBD0-E254-11DF-A4A3-F48B02F52B7F )
Emptying Hash slowly, doing key ADD9CE5A-E254-11DF-A4A3-F48B02F52B7F
Destroyed 3 ( value , ADD9CF5E-E254-11DF-A4A3-F48B02F52B7F )
Destroyed 3 ( key , ADD9CE5A-E254-11DF-A4A3-F48B02F52B7F )
Emptying Hash slowly, doing key ADD9D0DA-E254-11DF-A4A3-F48B02F52B7F
Destroyed 4 ( value , ADD9D1DE-E254-11DF-A4A3-F48B02F52B7F )
Destroyed 4 ( key , ADD9D0DA-E254-11DF-A4A3-F48B02F52B7F )
Emptying Hash slowly, doing key ADD9D38C-E254-11DF-A4A3-F48B02F52B7F
Destroyed 5 ( value , ADD9D49A-E254-11DF-A4A3-F48B02F52B7F )
Destroyed 5 ( key , ADD9D38C-E254-11DF-A4A3-F48B02F52B7F )