Here's an interesting problem, and maybe someone can educate me on what's
going on with it. I suspect that Devel::Size has a problem with tied
objects but I couldn't find anyone talking about it. While investigating
some stuff for Mastering Perl, I
wanted to see how much memory I could save (trading for speed) by packing
an array into a scalar, like Tie::Array::PackedC does. If I'm not
using an array, I shouldn't have to incur the scalar variable overhead for
every element, which could be 20 bytes or so.
I noticed that calling Devel::Size::total_size() on a tied
array (haven't tried the other structures) returns a number that seems
singularly dependent on that value that FETCHSIZE returns.
It took me a while to suss this out, but I finally created this mostly
empty class. The FETCHSIZE method simply returns the value I
passed to TIEARRAY.
(If you want to play with this, I've put up a tarball on my Mastering Perl site:
Tie-Array-Null-0.01.tar.gz)
package Tie::Array::Null;
# $Id: Cycle.pm,v 1.12 2005/03/08 22:29:30 comdog Exp $
use strict;
use base qw(Tie::Array);
use vars qw( $VERSION );
$VERSION = 0.01;
sub TIEARRAY { bless \ $_[1], $_[0] }
sub FETCHSIZE { ${ $_[0] } }
sub STORE { undef }
sub FETCH { undef }
sub STORESIZE { }
sub EXTEND { }
sub CLEAR { }
sub EXISTS { 0 }
sub DESTROY { }
"Tie::Array::Null";
The module doesn't store anything, and I don't expect the tied array size
to grow. Devel::Size::total_size( @tied_array ), I think,
should report something small and constant no matter what I do. I wrote a
test script to inspect the sizes as I add elements to the array. I suspect
that Devel::Size is counting that same thing multiple times, but
my internals Kung-Fu isn't strong enough to point out just where that's
happening.
#!/usr/bin/perl
# $Id$
use strict;
use Test::More 'no_plan';
use Devel::Size qw(total_size);
use Tie::Array::Null;
foreach my $size ( 0, 1, 5, 10, 100 )
{
report( $size )
}
pass();
sub report {
my $size = shift;
my $object = tie my( @tied_array ), 'Tie::Array::Null', $size;
isa_ok( $object, 'Tie::Array::Null' );
my $tied_array_size = total_size( \@tied_array );
my @regular_array = ();
print STDERR "\n----Testing for size $size-----\n";
print STDERR "Tied array size before is " .
total_size( \@tied_array ) . "\n";
print STDERR "Regular array size before is " .
total_size( \@regular_array ) . "\n";
print STDERR "-" x 73, "\n";
printf STDERR "%5s %5s %5s %5s\n", qw(iter tied len reg);
for( my $i = 0; $i < 1000; $i++ )
{
$tied_array[$i] = 'T';
push @regular_array, 'T';
unless( $i % 100 )
{
printf STDERR "%5d %5d %5d %5d\n",
$i,
total_size( \@tied_array ),
total_size( \$object ),
total_size( \@regular_array );
}
}
}
Once you run that code, change the number in FETCHSIZE and
run the test script again. The number Devel::Size::total_size( @tied_array )
changes, roughly according to some offset along with a fixed number multiplied
by the number FETCHSIZE returns (and that fixed number probably
matters on your platform and particular compilation options). The actual
object size grows as I expect (according to what it stores), but I don't
beleive the numbers for the "tied" column.
----Testing for size 0-----
Tied array size before is 108
Regular array size before is 56
--------------------------------------------------------------------
iter tied obj reg
0 108 62 94
100 108 62 3174
200 108 62 6286
300 108 62 9910
400 108 62 12510
500 108 62 15110
600 108 62 19758
700 108 62 22358
800 108 62 24958
900 108 62 27558
----Testing for size 1-----
Tied array size before is 220
Regular array size before is 4132
--------------------------------------------------------------------
iter tied obj reg
0 220 62 4158
100 220 62 6758
200 220 62 9358
300 220 62 11958
400 220 62 14558
500 220 62 17158
600 220 62 19758
700 220 62 22358
800 220 62 24958
900 220 62 27558
----Testing for size 5-----
Tied array size before is 556
Regular array size before is 4132
-------------------------------------------------------------------
iter tied obj reg
0 556 62 4158
100 556 62 6758
200 556 62 9358
300 556 62 11958
400 556 62 14558
500 556 62 17158
600 556 62 19758
700 556 62 22358
800 556 62 24958
900 556 62 27558
----Testing for size 10-----
Tied array size before is 976
Regular array size before is 4132
--------------------------------------------------------------------
iter tied obj reg
0 976 63 4158
100 976 63 6758
200 976 63 9358
300 976 63 11958
400 976 63 14558
500 976 63 17158
600 976 63 19758
700 976 63 22358
800 976 63 24958
900 976 63 27558
----Testing for size 100-----
Tied array size before is 8536
Regular array size before is 4132
--------------------------------------------------------------------
iter tied obj reg
0 8536 64 4158
100 8536 64 6758
200 8536 64 9358
300 8536 64 11958
400 8536 64 14558
500 8536 64 17158
600 8536 64 19758
700 8536 64 22358
800 8536 64 24958
900 8536 64 27558
Curiously, once I fix a few bugs in Tie::Array::PackedC's STORE
method (so it correctly updates the count and extends the "array" when necessary),
it has this problem too. Indeed, it wasn't until I realized that the FETCHSIZE
method from that module returned the wrong value that I was led to the idea that
this problem has something to do with how FETCHSIZE and Devel::Size
interact.