ID:               33595
 Comment by:       ruslan dot kyrychuk at gmail dot com
 Reported By:      rodricg at sellingsource dot com
 Status:           Assigned
 Bug Type:         Class/Object related
 Operating System: *
 PHP Version:      6CVS-2005-08-02
 Assigned To:      dmitry
 New Comment:

Maybe solutution can be to call destructor every time when new object
is assigned to old reference?
Example:
<?php
class A {
    function __construct () {
        $this->b = new B($this);
    }
    function __destruct () {
        $this->b->__destruct();
    }
}

class B {
    function __construct ($parent = NULL) {
        $this->parent = $parent;
    }
    function __destruct () {
        unset($this->parent);
    }
}

for ($i = 0 ; $i < 1000000 ; $i++) {
    $a = new A();
    $a->__destruct();
}

echo number_format(memory_get_usage());
?>

$a->__destruct(); can be called automatically because new reference is
created. Then writing correct destructors will solve this issue.

Or maybe I missing something?


Previous Comments:
------------------------------------------------------------------------

[2006-05-04 14:08:22] frode at coretrek dot com

I worked around this exact problem by using a proxy class with a
destructor that explicitly breaks the cycle; I got the idea from a
perl.com[1] article describing how perl suffers from the same problem.
It's also interesting to note that perl has chosen a different (less
elegant) solution to the problem than python, by introducing weak
references.

[1] http://www.perl.com/pub/a/2002/08/07/proxyobject.html

------------------------------------------------------------------------

[2006-04-13 06:24:02] seufert at gmail dot com

I have been experiencing this problem. Unfortunately i have an
application which relies heavily on a class->driver arrangement where
both the class and the driver class need a reference to each other. I
was wondering if we could have a way of getting an uncounted reference
to the object to pass to the child? So the child would have a reference
to the parent, but it would not be counted, and therefore when all
external references to the parent are removed/unset, the parent will
GC, and then the child will be freed as usual.

Is this a workable solution? Even just a reference count decrement
would work. Not a perfect solution, but it would solve calling
descructors all the time.

------------------------------------------------------------------------

[2006-02-22 15:12:21] K dot Londenberg at librics dot de

The problem with circular references is a known weakness of reference
counting schemes. Python uses a workaround (cycle detector). 

Excerpt from
http://wingware.com/psupport/python-manual/2.4/ext/refcounts.html:

"
While Python uses the traditional reference counting implementation, it
also offers a cycle detector that works to detect reference cycles. This
allows applications to not worry about creating direct or indirect
circular references; these are the weakness of garbage collection
implemented using only reference counting. Reference cycles consist of
objects which contain (possibly indirect) references to themselves, so
that each object in the cycle has a reference count which is non-zero.
Typical reference counting implementations are not able to reclaim the
memory belonging to any objects in a reference cycle, or referenced
from the objects in the cycle, even though there are no further
references to the cycle itself. "

Maybe this would also be a viable Strategy for PHP..

------------------------------------------------------------------------

[2006-01-19 10:31:05] letssurf at gmail dot com

Thank you for your solution. It's the same path we had taken here. We
had created a kill() method to do the same job. Shame it hasn't been
fixed.

Thank you again :)

------------------------------------------------------------------------

[2006-01-17 19:08:55] rodricg at sellingsource dot com

You can avoid the memory leak by manually calling the destructors and
unsetting the recursive ref:

<?php
class A {
    function __construct () {
        $this->b = new B($this);
    }
    function __destruct () {
        $this->b->__destruct();
    }
}

class B {
    function __construct ($parent = NULL) {
        $this->parent = $parent;
    }
    function __destruct () {
        unset($this->parent);
    }
}

for ($i = 0 ; $i < 1000000 ; $i++) {
    $a = new A();
    $a->__destruct();
}

echo number_format(memory_get_usage());
?>

------------------------------------------------------------------------

The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
    http://bugs.php.net/33595

-- 
Edit this bug report at http://bugs.php.net/?id=33595&edit=1

Reply via email to