Sorry, I should've been more precise. Perl constructs an intermediate list of arrays, which is held on Perl's stack (in its entirety) before it is assigned to the final array. This temporarily consumes a lot of memory, which is not returned to the OS (at least not with typical Unix-builds of Perl). Of course, the memory is returned to Perl's own memory pool, so it may be reused later. But the peak memory usage of the process increases.
As soon as references are involved, the additional temporary data only involves the first level elements, i.e. the array references in this case. The referenced data isn't being duplicated, of course. Still, if the ratio of the references to the payload data is bad (i.e. scond-level arrays with only few non-complex items), there can still be considerable overhead.
Just for comparison, for anyone interested:
sub mem {
print "$_[0]:\n";
system "/bin/ps", "-osize,vsize", $$;
}
my @a;
my %tests = (
# immediate data - no references
iter_flat =>
sub {
my $n = shift;
push @a, $_*42 for 1..$n;
},
func_flat =>
sub {
my $n = shift;
@a = map $_*42, 1..$n;
},
# indirect/referenced data
iter_ref =>
sub {
my $n = shift;
push @a, [ $_*42 ] for 1..$n;
},
func_ref =>
sub {
my $n = shift;
@a = map [ $_*42 ], 1..$n;
}
);
my $what = shift @ARGV;
my $n = shift @ARGV || 10_000_000;
mem("before");
$tests{$what}->($n);
mem("after");
$ ./883539.pl iter_flat
before:
SZ VSZ
608 22032
after:
SZ VSZ
395196 416620
$ ./883539.pl func_flat
before:
SZ VSZ
608 22032
after:
SZ VSZ
1390892 1412316 # map needs 3.5 times as much
$ ./883539.pl iter_ref
before:
SZ VSZ
608 22032
after:
SZ VSZ
1547832 1569256
$ ./883539.pl func_ref
before:
SZ VSZ
608 22032
after:
SZ VSZ
2571632 2593056 # map needs 1.7 times as much
|