in reply to Re: Freeing memory, revisited (Linux)
in thread Freeing memory, revisited (Linux)

The three x expressions are constant folded at compile time

Nice theory... but if the size to allocate isn't known before run-time, you still do get the same behavior.  Even in slightly modified cases like these, where the $y should definitely go out of scope (and thus the memory behind it be available for reuse):

$ strace -e mmap,munmap perl -e '$n=2**20; $x="x" x $n; {my $y=$x}{my +$y=$x}{my $y=$x}' ... mmap(NULL, 1052672, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, - +1, 0) = 0x7fa5d43d3000 mmap(NULL, 1052672, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, - +1, 0) = 0x7fa5d2ecd000 mmap(NULL, 1052672, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, - +1, 0) = 0x7fa5d2dcc000 mmap(NULL, 1052672, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, - +1, 0) = 0x7fa5d2ccb000 mmap(NULL, 1052672, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, - +1, 0) = 0x7fa5d2bca000 munmap(0x7fa5d2bca000, 1052672) = 0 munmap(0x7fa5d2ccb000, 1052672) = 0 munmap(0x7fa5d2dcc000, 1052672) = 0 munmap(0x7fa5d43d3000, 1052672) = 0

Personally, I'd consider this a bug.

Note that if you write for (1..3) {my $y = $x} instead of spelling out {my $y = $x} three times, the memory is being reused just fine:

$ strace -e mmap,munmap perl -e '$n=2**20; $x="x" x $n; for (1..3) {my + $y=$x}' ... mmap(NULL, 1052672, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, - +1, 0) = 0x7f9d9bdfd000 mmap(NULL, 1052672, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, - +1, 0) = 0x7f9d9a8f7000 mmap(NULL, 1052672, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, - +1, 0) = 0x7f9d9a7f6000 munmap(0x7f9d9a7f6000, 1052672) = 0 munmap(0x7f9d9bdfd000, 1052672) = 0

Replies are listed 'Best First'.
Re^3: Freeing memory, revisited (Linux)
by dave_the_m (Monsignor) on May 05, 2011 at 15:09 UTC
    Nice theory
    Simply the truth.

    In your run-time example, a different mechanism causes the allocations to be retained. Every sub-expression that returns a result has a "pad temp" allocated to it to store the temporary result. The values in the pad temp are retained until the sub is freed, but they are re-used. i.e. in the following:

    sub f { return "x" x $_[0] } f(100_000); f(5); f(200_000);
    a single temp will be stored within f's pad. On the first call it will hold a scalar of length 100_000, which gets retained. On the second call, the scalar is shrunk to length 5 (but not freed), and on the third call the scalar is realloced to grow to 200_000, and finally freed when the sub f is destroyed.

    Dave.

      Simply the truth.

      So if constant folding (+ allocation) and storing the results as part of the code happens at compile time, how would you explain that the (runtime-)prints in the strace output of the following snippet are interleaved with the allocations?

      {print STDERR "1"; "x" x 2**20} {print STDERR "2"; "x" x 2**20} {print STDERR "3"; "x" x 2**20}
      $ strace -e mmap,munmap,write ./903114.pl ... write(2, "1", 11) = 1 mmap(NULL, 1052672, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, - +1, 0) = 0x7fe6d7315000 write(2, "2", 12) = 1 mmap(NULL, 1052672, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, - +1, 0) = 0x7fe6d5e0f000 write(2, "3", 13) = 1 mmap(NULL, 1052672, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, - +1, 0) = 0x7fe6d5d0e000 munmap(0x7fe6d5d0e000, 1052672) = 0 munmap(0x7fe6d5e0f000, 1052672) = 0 munmap(0x7fe6d7315000, 1052672) = 0

      Also,

      $ perl -MO=Concise,-exec ./903114.pl ... 11 <$> const[PV "x"] s 12 <$> const[IV 1048576] s 13 <2> repeat[t9] vK/2 <--- ...

      seems to suggest that the repetition operator is applied at runtime.

        Ah, so repeat isn't constant folded. In which case, it's always the pad temps that retain the allocations.

        Dave.