print 'My enemy must ', $enemy->obey(),
undef($enemy),
'. His phaser is named ', $phaser->{name},
eval('$enemy->exterminate()'),
". Bye!\n";
that I suspect that perl may be putting a reference to the thing $enemy refers to on the stack for the purpose of calling the obey() method (and possibly for the undef thing, too). So that we'd have something like this:
*** Before print statement ***
$enemy------------------------->Dalek:{phaser=> + } (ref=1)
|
+---------------+
v
$phaser------------------------>Phaser:{name=> + } (ref=2)
|
+--------------+
v
'Exterminator' (ref=1)
argument stack: -empty-
*** After print setup, before print executes ***
$enemy------------------------->Dalek:{phaser=> + } (ref=2)<-+
| |
+---------------+ |
v |
$phaser------------------------>Phaser:{name=> + (ref=2) |
| |
+--------------+ |
v |
'Exterminator' (ref=2) |
^ |
+--------------+ |
argument stack: '. Bye!\n' | |
eval('$enemy->exterminate()' | |
ref---------------------------+ |
'. His phaser is named ' |
undef($enemy) |
obey()<-ref---------------------------------+
'My enemy must '
At this point, I'm guessing the stack contains a reference to the Dalek that
$enemy also points to, so it can call the obey method.
*** Executing through print, just after undef step ***
$enemy--->undef Dalek:{phaser=> + } (ref=1)<-+
| |
+---------------+ |
v |
$phaser------------------------>Phaser:{name=> + (ref=2) |
| |
+--------------+ |
v |
'Exterminator' (ref=2) |
^ |
+--------------+ |
argument stack: '. Bye!\n' | |
eval('$enemy->exterminate()' | |
ref---------------------------+ |
'. His phaser is named ' |
undef($enemy) |
obey()<-ref---------------------------------+
'My enemy must '
Here, we've already executed the obey() method so the string gets printed, and
we've just executed undef, so the link between $enemy and the Dalek is now broken.
But the argument stack for print still holds the reference to the Dalek.
*** Print just finished, now removing items from stack ... ***
$enemy--->undef Dalek:{phaser=> + } (ref=1)<-+
| |
+---------------+ |
v |
$phaser------------------------>Phaser:{name=> + (ref=2) |
| |
+--------------+ |
v |
'Exterminator' (ref=1) |
|
argument stack: obey()<-ref---------------------------------+
'My enemy must '
Most of the argument stack for the print statement is gone, the next item to go is
the reference of interest. (Note: the reference count to the 'Exterminaor' string
has already dropped back to 1.) So perl dutifully reduces the references count for the
item on the stack, and notices the count went to 0:
$enemy--->undef Dalek:{phaser=> + } (ref=0)<-+
| |
+---------------+ |
v |
$phaser------------------------>Phaser:{name=> + (ref=2) |
| |
+--------------+ |
v |
'Exterminator' (ref=1) |
|
argument stack: obey()<-ref---------------------------------+
'My enemy must '
...at which point it tells the Dalek to go DESTROY itself. While it destroys
itself, it discards the reference to the Phaser (reducing its reference count):
$enemy--->undef Dalek:{phaser=> } (ref=0)<-+
|
$phaser------------------------>Phaser:{name=> + (ref=1) |
| |
+--------------+ |
v |
'Exterminator' (ref=1) |
|
argument stack: obey()<-ref---------------------------------+
'My enemy must '
The Phaser still has a reference, so it's going to stick around. When the DESTROY method
returns, perl then frees the Dalek memory, and continues to remove items from the
argument stack:
$enemy--->undef {FREE MEMORY }
$phaser------------------------>Phaser:{name=>'Exterminator'} (ref=1)
argument stack: 'My enemy must '
I guess I should've put a reference count on the 'Exterminator' string, as well, but I didn't think of it until after I drew all of that, and I'm not quite ambitious enough to fix that oversight.
Here's a bit of code I came up with in an attempt to lend some weight to my theory. It's not proof, as I can't think of a way to examine the variables in the middle of stack cleanup (short of running perl under gdb):
The results are a bit tedious to read through, though:
Update: I went ahead and updated the diagram to show the reference counts for the 'Exterminated' string as well. It make the node a bit longer, but I think it helps illustrate things. I also added a couple readmore tags to make a long post somewhat shorter.
...roboticus
When your only tool is a hammer, all problems look like your thumb. |