in reply to Freeing memory, revisited (Linux)

The three x expressions are constant folded at compile time, then the results are stored as part of the program code, and are only freed when the program is freed.

Dave.

Replies are listed 'Best First'.
Re^2: Freeing memory, revisited (Linux)
by Eliya (Vicar) on May 05, 2011 at 14:31 UTC
    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
      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.