DBIx-Class
view release on metacpan or search on metacpan
t/lib/DBICTest/Util/LeakTracer.pm view on Meta::CPAN
# replace all slot names
$slot_info->{slot_names} = { map {
my $name = $_;
$name =~ s/\(0x[0-9A-F]+\)/sprintf ('(%s)', $new_addr)/ieg;
($name => 1);
} keys %{$slot_info->{slot_names}} };
$reg->{$new_addr} = $slot_info;
}
}
}
sub visit_refs {
my $args = { (ref $_[0]) ? %{$_[0]} : @_ };
$args->{seen_refs} ||= {};
my $visited_cnt = '0E0';
for my $i (0 .. $#{$args->{refs}} ) {
next unless length ref $args->{refs}[$i]; # not-a-ref
my $addr = hrefaddr $args->{refs}[$i];
# no diving into weakregistries
next if $reg_of_regs{$addr};
next if $args->{seen_refs}{$addr}++;
$visited_cnt++;
my $r = $args->{refs}[$i];
$args->{action}->($r) or next;
# This may end up being necessarry some day, but do not slow things
# down for now
#if ( defined( my $t = tied($r) ) ) {
# $visited_cnt += visit_refs({ %$args, refs => [ $t ] });
#}
my $type = reftype $r;
local $@;
eval {
if ($type eq 'HASH') {
$visited_cnt += visit_refs({ %$args, refs => [ map {
( !isweak($r->{$_}) ) ? $r->{$_} : ()
} keys %$r ] });
}
elsif ($type eq 'ARRAY') {
$visited_cnt += visit_refs({ %$args, refs => [ map {
( !isweak($r->[$_]) ) ? $r->[$_] : ()
} 0..$#$r ] });
}
elsif ($type eq 'REF' and !isweak($$r)) {
$visited_cnt += visit_refs({ %$args, refs => [ $$r ] });
}
elsif (CV_TRACING and $type eq 'CODE') {
$visited_cnt += visit_refs({ %$args, refs => [ map {
( !isweak($_) ) ? $_ : ()
} values %{ scalar PadWalker::closed_over($r) } ] }); # scalar due to RT#92269
}
1;
} or warn "Could not descend into @{[ refdesc $r ]}: $@\n";
}
$visited_cnt;
}
# compiles a list of addresses stored as globals (possibly even catching
# class data in the form of method closures), so we can skip them further on
sub symtable_referenced_addresses {
my $refs_per_pkg;
my $seen_refs = {};
visit_namespaces(
action => sub {
no strict 'refs';
my $pkg = shift;
# the unless regex at the end skips some dangerous namespaces outright
# (but does not prevent descent)
$refs_per_pkg->{$pkg} += visit_refs (
seen_refs => $seen_refs,
action => sub { 1 },
refs => [ map { my $sym = $_;
# *{"${pkg}::$sym"}{CODE} won't simply work - MRO-cached CVs are invisible there
( CV_TRACING ? Class::MethodCache::get_cv("${pkg}::$sym") : () ),
( defined *{"${pkg}::$sym"}{SCALAR} and length ref ${"${pkg}::$sym"} and ! isweak( ${"${pkg}::$sym"} ) )
? ${"${pkg}::$sym"} : ()
,
( map {
( defined *{"${pkg}::$sym"}{$_} and ! isweak(defined *{"${pkg}::$sym"}{$_}) )
? *{"${pkg}::$sym"}{$_}
: ()
} qw(HASH ARRAY IO GLOB) ),
} keys %{"${pkg}::"} ],
) unless $pkg =~ /^ (?:
DB | next | B | .+? ::::ISA (?: ::CACHE ) | Class::C3 | B::Hooks::EndOfScope::PP::HintHash::.+
) $/x;
}
);
# use Devel::Dwarn;
# Ddie [ map
# { { $_ => $refs_per_pkg->{$_} } }
# sort
# {$refs_per_pkg->{$a} <=> $refs_per_pkg->{$b} }
# keys %$refs_per_pkg
# ];
$seen_refs;
}
( run in 0.669 second using v1.01-cache-2.11-cpan-5a3173703d6 )