Häufig steht man vor der Frage, wo genau eine Variable (oder allgemein ein Perl-Wert) referenziert wird.
Devel::FindRef von Marc Lehmann ist ein kleines Modul, mit dem man exakt herausfinden kann, wo eine bestimmte Variable referenziert wird, ob es einen Referenz-Zyklus gibt, oder welche closure den Wert noch referenziert.
Marc Lehmann hat Devel::FindRef in einem Lightning Talk auf dem 11. Deutschen Perl-Workshop in Frankfurt/Main vorgestellt.
Einfaches Beispiel
#!/usr/bin/perl use strict; use warnings; use Devel::FindRef; # Die Variable, die untersucht werden soll our $var = 'hi there'; # Ein paar Referenzen auf diese Variable my $global_my = \$var; our %global_hash = ( key1 => \$var ); our $global_hashref = { key2 => \$var }; testsub(); sub testsub { my $testsub_local = $global_hashref; print "Track für \$var '$var':\n"; print Devel::FindRef::track \$var; }
Das Programm erzeugt folgende Ausgabe:
Track für $var 'hi there': SCALAR(0x8169fe8) [refcount 5] is +- in the global $main::var. +- referenced by REF(0x8169fa8) [refcount 1], which is | in the lexical '$global_my' in CODE(0x8155318) [refcount 2], which is | +- the containing scope for CODE(0x81a5468) [refcount 3], which is | | in the global &main::testsub. | +- the main body of the program. +- referenced by REF(0x8169f28) [refcount 1], which is | in the member 'key2' of HASH(0x81550b8) [refcount 2], which is | +- referenced by REF(0x81a54c8) [refcount 1], which is | | in the lexical '$testsub_local' in CODE(0x81a5468) [refcount 3], which was seen before. | +- referenced by REF(0x81a5168) [refcount 1], which is | in the global $main::global_hashref. +- referenced by REF(0x8155308) [refcount 1], which is | in the member 'key1' of HASH(0x816a368) [refcount 1], which is | in the global %main::global_hash. +- referenced by REF(0x81551d8) [refcount 1], which is a temporary on the stack.
Die Ausgabe muss man sich anfangs wohl zwei- oder dreimal anschauen, danach wird es besser.
Beispiel: Verwendung von closures und weaken
#!/usr/bin/perl use strict; use warnings; use Devel::FindRef; use Scalar::Util; our $var = 'hi there'; my $global_my = \$var; our %global_hash = ( key1 => \$var); our $global_hashref = { key2 => \$var }; sub testsub { my $testsub_local = $global_hashref; print "Track fuer \$var '$var':\n"; print Devel::FindRef::track \$var; } my $closure = sub { my $closure_var = \$_[0]; Scalar::Util::weaken (my $weak_ref = \$var); testsub(); }; $closure->($var);
Das Programm erzeugt folgende Ausgabe:
Track fuer $var 'hi there': SCALAR(0x8169f58) [refcount 6] is +- referenced by REF(0x81a5640) [refcount 1], which is | in the lexical '$closure_var' in CODE(0x81a5600) [refcount 4], which is | +- the closure created at f2.pl:22. | +- referenced by REF(0x81a5440) [refcount 1], which is | | in the lexical '$closure' in CODE(0x8155318) [refcount 2], which is | | +- the containing scope for CODE(0x81a5460) [refcount 3], which is | | | in the global &main::testsub. | | +- the main body of the program. | +- in the lexical '&' in CODE(0x8155318) [refcount 2], which was seen before. +- referenced by REF(0x816a008) [refcount 1], which is | in the lexical '$global_my' in CODE(0x8155318) [refcount 2], which was seen before. +- in the global $main::var. +- referenced by REF(0x8169f28) [refcount 1], which is | in the member 'key2' of HASH(0x81550b8) [refcount 2], which is | +- referenced by REF(0x81a54d0) [refcount 1], which is | | in the lexical '$testsub_local' in CODE(0x81a5460) [refcount 3], which was seen before. | +- referenced by REF(0x81a51a0) [refcount 1], which is | in the global $main::global_hashref. +- referenced by REF(0x8155308) [refcount 1], which is | in the member 'key1' of HASH(0x816a368) [refcount 1], which is | in the global %main::global_hash. +- referenced by REF(0x81551d8) [refcount 1], which is a temporary on the stack.
Cool!
Jetzt kommentieren