Hay casos en que sería muy importante saber cuánto usa cada variable en Perl. Para esto el módulo Devel::Size ofrece dos funciones. Tanto en size como total_size aceptan una referencia a una variable o una estructura de datos. La diferencia entre ellos es que en las estructuras de datos complejas (aka. arrays y hashes), size sólo devuelve la memoria utilizada por la estructura, no por los datos.

Hay que señalar algunas diferencias entre la memoria que Perl solicita, a lo que Devel::Size informe, y lo que en realidad ha asignado el sistema operativo. Si está interesado, hay una buena explicación en la documentación de Devel::Size

El siguiente script intenta mostrar algunos valores básicos:

use strict;
use warnings;
use 5.010;

use Devel::Size qw(size total_size);

my $x;
my @y;
my %z;

say '                           size  total_size';
both('SCALAR', \$x);        #    24    24
both('ARRAY',  \@y);        #    64    64
both('HASH',   \%z);        #   120   120
both('CODE', sub {} );      #  8452  8452
say '';

both('SCALAR', \$x);        #  24    24
$x = 'x';
both('SCALAR-1', \$x);      #  56    56
$x = 'x' x 15;
both('SCALAR-15', \$x);     #  56    56
$x = 'x' x 16;
both('SCALAR-16', \$x);     #  72    72
$x = 'x' x 31;
both('SCALAR-31', \$x);     #  72    72
$x = 'x' x 32;
both('SCALAR-32', \$x);     #  88    88
$x = '';
both('SCALAR=""', \$x);     #  88    88
$x = undef;
both('SCALAR=undef', \$x);  #  88    88
undef $x;
both('undef SCALAR', \$x);  #  40    40
say '';

both('ARRAY',  \@y);               #    64    64
@y = ('x');
both('ARRAY-1', \@y);              #    96   152
@y = ('x' x 15);
both('ARRAY-15', \@y);             #    96   152
@y = ('x' x 16);
both('ARRAY-16', \@y);             #    96   168
@y = ('x' x 31);
both('ARRAY-31', \@y);             #    96   168
@y = ('x' x 32);
both('ARRAY-32', \@y);             #    96   184
@y = ('x') x 2;
both('ARRAY-1-1', \@y);            #    96   208
@y = ('x') x 4;
both('ARRAY-1-1-1-1', \@y);        #    96   320
@y = ('x') x 5;
both('ARRAY-1-1-1-1-1', \@y);      #   104   384
@y = ('x') x 6;
both('ARRAY-1-1-1-1-1-1', \@y);    #   112   448
@y = ('x') x 7;
both('ARRAY-1-1-1-1-1-1-1', \@y);  #   128   520
@y = ();
both('ARRAY = ()', \@y);           #   128   128
undef @y;
both('undef ARRAY', \@y);          #    64    64
say('');

both('HASH',   \%z);                       #  120   120
%z = ('x' => undef);
both('HASH x => undef',   \%z);            #  179   203
%z = ('x' => "x");
both('HASH x => "x"',   \%z);              #  179   235
%z = ('x' x 10 => "x" x 20);
both('HASH "x" x 10 => "x" x 20',   \%z);  #  188   260
for my $c (qw(a b c d e f g h i)) {
    $z{$c x 10} = $c x 20;
}
both('HASH 10 * 10 + 10 * 20',   \%z);     #  864  1584
%z = ();
both('HASH=()',   \%z);                    #  184   184
undef %z;
both('undef HASH',   \%z);                 #  120   120
my $o = bless \%z,'Some::Very::Long::Class::Name::That::Probably::Noone::Uses';
both('blessed HASH', $o);                  #  120   120
say('');

both('CODE', sub {}  );                   #  8516  8516
both('CODE2', sub { my $w }  );           #  8612  8612
both('CODE3', sub { my $w = 'a' }  );     #  8820  8820

sub both {
    my ($name, $ref) = @_;
    printf "%-25s %5d %5d\n", $name, size($ref), total_size($ref);
}

El ambiente

Estos resultados fueron generados sobre 64 bit OSX, ejecutando perl 5.18.2 usando Devel::Size 0.79. (Obtuve el mismo resultado cuando ejecuté el escript sobre 5.18.1, excepto que los valores para el CODE'references fueron de 8 bytes mas pequeños).

Algunas observaciones

El tamaño del código-referencias parece enorme. Me pregunto si estos números son correctos.

Extrañamente bless no cambia el tamaño de la referencia. O por lo menos, no se divulga.

Se asigna memoria en trozos de 16 bytes para cadens. Por lo tanto es la memoria utilizada por una larga cadena de caracteres 1 el mismo que utiliza por una larga cadena de 15 caracteres.

Ni ajustar la cadena a la cadena vacía ($x = '';), ni asignar undef a él ($x = undef;) reduce el uso de la memoria. Tuve que llamar undef $x; por eso. Incluso entonces volvió sólo a 40, en lugar de la original 24.

En matrices, cada elemento utiliza 8 bytes + memoria asignada para el contenedor escalar + los datos.

Ajuste @y = (); eliminar la asignación de memoria de la fecha (o por lo menos total_size no se muestra nada más) Llamando undef @y; también libera la memoria asignada a la estructura.

En hashes es aún más complejo. No intento describirlo. La documentación de Devel::Size tiene alguna explicación.

El resultado actual se observa algo como esto

                          size    total_size
SCALAR                       24    24
ARRAY                        64    64
HASH                        120   120
CODE                       8452  8452

SCALAR                       24    24
SCALAR-1                     56    56
SCALAR-15                    56    56
SCALAR-16                    72    72
SCALAR-31                    72    72
SCALAR-32                    88    88
SCALAR=""                    88    88
SCALAR=undef                 88    88
undef SCALAR                 40    40

ARRAY                        64    64
ARRAY-1                      96   152
ARRAY-15                     96   152
ARRAY-16                     96   168
ARRAY-31                     96   168
ARRAY-32                     96   184
ARRAY-1-1                    96   208
ARRAY-1-1-1-1                96   320
ARRAY-1-1-1-1-1             104   384
ARRAY-1-1-1-1-1-1           112   448
ARRAY-1-1-1-1-1-1-1         128   520
ARRAY = ()                  128   128
undef ARRAY                  64    64

HASH                        120   120
HASH x => undef             179   203
HASH x => "x"               179   235
HASH "x" x 10 => "x" x 20   188   260
HASH 10 * 10 + 10 * 20      864  1584
HASH=()                     184   184
undef HASH                  120   120
blessed HASH                120   120

CODE                       8516  8516
CODE2                      8612  8612
CODE3                      8820  8820