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