|
Posted by Alan Pinstein on 12/08/05 18:20
/* comments inline */
On Dec 8, 2005, at 2:34 AM, Curt Zirzow wrote:
> On Wed, Dec 07, 2005 at 09:30:36PM -0500, Alan Pinstein wrote:
>>
>> On Dec 7, 2005, at 12:36 AM, Curt Zirzow wrote:
>>>
>>> I'm not sure how you mean a weak reference, and well a refcount is
>>> rather meaning less in php userland.
>>
>> So, this gets interesting. I don't know if you're familiar with the
>> circular-reference problem. But if you have two instances that have
>> references to each other, even once you remove all references to the
>> objects, they will not be GC'd since they have a mutual deadlock on
>> each other:
>>
>> $a = new MyObj;
>> $b = new MyObj;
>> $a->setB($b); // does $this->b = $b;
>> $b->setA($a); // does $this->a = $a;
>>
>> $a = NULL;
>> $b = NULL;
>>
>> The actual instances pointed to by $a and $b WILL NOT GET FREED HERE
>> as you would *wish*. However this is expected behavior.
>
> I would have to disagree with the 'as you would *wish*' part.
>
> if I pass something to a function/method via copy (vs reference) i
> would hardly expect code outside the function/method to affect
> their existance.
I'll ask you to reconsider :) Let me explain...
After both $a and $b are set to null, your script NO LONGER HAS ANY
REFERENCES TO $a OR $b! The objects are now "orphaned" as far as you
are concerned. So if you cannot access the objects, why would you
still want them to take up memory?
This is why I say "as you would *wish*. The fact that the objects are
not freed here is a memory leak. Now, the party responsible for the
memory leak is the coder, NOT PHP. PHP is doing the "right" thing
because according to its internal GC both $a and $b still have a
refcount of 1.
So, it is up to the developer to make sure that they code in such a
way that the objects do not have a refcount deadlock in such a
situation. This is the point of my entire thread; I want to confirm
the correct way to do this in PHP.
Apple's Cocoa documentation has a good explanation of this. Read the
sections "Retaining Objects", "Retain Cycles", and "Weak References"
that begin here. It's just a few paragraphs. Cocoa's memory
management and garbage collection is very similar in concept to
PHP's, except that you must EXPLICITLY control reference counts.
[ watch for wrapped link ]
http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/
Concepts/ObjectOwnership.html#//apple_ref/doc/uid/20000043-1000698
>> Only by changing MyObj to store "weak references", that is references
>> to the objects that are NOT reference-counted, can you get the GC to
>> free the instances.
>>
>> function setB(&$B) { $this->b = &$a; }
>> function setA(&$B) { $this->a = &$b; }
>>
>> Now, the instances will be freed when the $a and $b are null'd out.
>
> I think you meant to type:
>
> function setB(&$a) { $this->b = &$a; }
> function setA(&$b) { $this->a = &$b; }
Oops yes.
> And consider the definition written as:
>
> function setB(&$a) { $this->b = $a; }
> function setA(&$b) { $this->a = $b; }
>
> does the $a = null; and $b = null; outside the class cause the
> objects to get null'd inside the class as well?
Well, this is different from what I wrote; you took away the &
operator on $a and $b in the assignment. This then causes the
refcounts to be bumped, so in the code as YOU'VE re-written it, in
fact nulling the objects outside the class DOES NOT cause them to be
released.
However, let's talk about the version I wrote:
> function setB(&$a) { $this->b = &$a; }
> function setA(&$b) { $this->a = &$b; }
In this case, nulling out the $a and $b that were passed in DOES in
fact release these linked objects. But that's OK, because you don't
have a way to access these objects anymore anyway, as described above.
Now, this example is just for explanatory purposes; typically you do
not have two objects that mutually store weak references to each
other. Typical, one side of the two-way link typically is the "owner"
and has a "refcounted" reference to the other object, while the other
side of the link has the weak reference to the other object. Normally
the parent object retains, and the child object has a weak reference.
>> So, while I now feel more confident of how references act with
>> respect to objects (which is, they act the same as they do for any
>> variable), I still am not sure what "$this->this" is and why it
>> worked so magically.
>
> You lost me on your $this->this statement.
Well, in reality, with a parent-child situation, you have
$a->addChildObject($b);
class A
{
function addChildObject($b)
{
$this->children[] = $b; // refcount+1
$b->setParent($this);
}
}
class B
{
function setParent(&$b)
{
$this->parent = &$b;
}
}
However, I tried this, and it doesn't work. The $b->setParent($this)
line still bumps the refcount. After experimenting, I realize that if
I do $b->setParent($this->this) then it works as expected.
But what the heck is $this->this?
And this is my question, why does this work? Can I count on it? Why
doesn't just referencing $this work as expected?
I understand that this is a bit complicated, as memory management
often is. But memory leaks are a big deal when writing PHP CLI
scripts that import say 75,000 records and leak 4k per iteration.
Alan
Navigation:
[Reply to this message]
|