diff Lib/IMPL/Profiler/Memory.pm @ 188:029c9610528c

Memory leak tests in IMPL::Web::View
author cin
date Tue, 03 Apr 2012 20:08:42 +0400
parents 16ada169ca75
children 08015e2803f1
line wrap: on
line diff
--- a/Lib/IMPL/Profiler/Memory.pm	Tue Apr 03 07:54:25 2012 +0400
+++ b/Lib/IMPL/Profiler/Memory.pm	Tue Apr 03 20:08:42 2012 +0400
@@ -4,54 +4,106 @@
 use Carp qw(longmess shortmess);
 use Scalar::Util qw(refaddr weaken isweak);
 
-my %instances;
+my %listeners;
+my $trapped;
 
 BEGIN {
-    *CORE::GLOBAL::bless = sub {
-        $_[1] |= caller unless $_[1];
-        my $ref = CORE::bless $_[0],$_[1];
+	$trapped = 0;
+}
 
-        my $id = refaddr($ref);
+sub import {
+	if (not $trapped) {
+	    *CORE::GLOBAL::bless = sub {
+	        $_[1] |= caller unless $_[1];
+	        my $ref = CORE::bless $_[0],$_[1];
+	
+	        $_->track($ref) foreach values %listeners;
+	
+	        return $ref;
+	    };
+	    $trapped = 1;
+	}
+}
 
-        $instances{$id} = {
-            Class => $_[1],
-            WeakRef => $ref
-        };
+sub _ConnectListener {
+	my ($self,$listener) = @_;
+	
+	die "Invalid listener" unless ref $listener;
+	
+	$listeners{refaddr($listener)} = $listener;
+}
 
-        weaken($instances{$id}{WeakRef});
+sub _RemoveListener {
+	my ($self,$listener) = @_;
+	
+	die "Invalid listener" unless ref $listener;
+	
+	delete $listeners{refaddr($listener)};
+}
 
-        return $ref;
-    }
+sub Monitor {
+	my ($self,$code) = @_;
+	
+	my $data = IMPL::Profiler::Memory::Data->new();
+	
+	$data->Monitor($code);
+	
+	return $data; 
 }
 
-sub DumpAlive {
-    my ($hout) = @_;
-    $hout = *STDOUT unless $hout;
-    print $hout "Alive objects table\n";
-    print $hout "-------------------\n";
-    while (my ($id,$info) = each %instances) {
-        delete $instances{$id} and next unless $info->{WeakRef};
-        print "$info->{Class} $id: $info->{WeakRef}\n";
-    }
+package IMPL::Profiler::Memory::Data;
+use parent qw(IMPL::Object::Fields);
+
+use Data::Dumper();
+use Scalar::Util qw(refaddr weaken isweak);
+
+use fields qw( objects );
+
+sub CTOR {
+	my $this = shift;
+	$this->{objects} = [];
+}
+
+sub track {
+	my $i = scalar @{$_[0]->{objects}};
+	$_[0]->{objects}[$i] = $_[1];
+	weaken($_[0]->{objects}[$i]);
+}
+
+sub Purge {
+	my $this = shift;
+	
+	return $this->{objects} = [ grep defined($_), @{$this->{objects}}];
 }
 
-sub StatClasses {
-    my ($hout) = @_;
-    $hout = *STDOUT unless $hout;
-    print $hout "Statistics by class\n";
-    print $hout "-------------------\n";
-    my %stat;
-    while (my ($id,$info) = each %instances) {
-        #$stat{$info->{Class}}{total} ++;
-        delete $instances{$id} and next unless $info->{WeakRef};
-        $stat{$info->{Class}}{alive} ++;
-    }
+sub Dump {
+	my $this = shift;
+	return Data::Dumper->Dump($this->{objects});
+}
 
-    print $hout "$_ $stat{$_}{alive} \n" foreach sort keys %stat;
+sub isLeak {
+	my ($this) = @_;
+	$this->Purge();
+	return ( scalar(@{$this->{objects}}) > 0);
 }
 
-sub Clear {
-    undef %instances;
+sub Monitor {
+	my ($this,$code) = @_;
+	
+	die "A reference to a subroutine is required" unless ref $code;
+	
+	IMPL::Profiler::Memory->_ConnectListener($this);
+	eval {
+		$code->();
+	};
+	my $err = $@;
+	IMPL::Profiler::Memory->_RemoveListener($this);
+	
+	die $err if $err;
+	
+	return;
 }
 
+
+
 1;