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
|