Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

destructing an object with references to itself

While debugging a piece of code that was exhausting the memory, I found a very interesting problem, and most importantly I don't know how to fix it.

The application consists roughly of a single Survey object, which contains a number of Question objects. The Question objects contain a reference to the Survey they're in, this is needed to be able to fetch answers from other Questions for instance.


The following loop was causing the memory overflow:

foreach ( $survey_ids_arr as $survey_id ) {
    $Survey = new Survey( $survey_id );
}

Nothing really exotic is happening in the Survey constructor;

  • fetching its properties from the database
  • fetching all questions' properties from the database
  • creating a Question object for each question (passing a reference to $this)
  • adding all Question objects to an internal array

and from looking at the code, you would say that in each iteration the object is cleared from memory because the $Survey variable is overwritten. Right?? Wrong :)

The memory is piling up as the script goes through the loop - adding memory_get_usage() calls shows that the memory used by the Survey object isn't freed as expected, at the moment another object is assigned to the $Survey variable. Even calling unset( $Survey ) at the end of the loop does not free the memory.


The culprit are the references to $this that are passed to the Question objects upon creation. These references prevent the object to be cleared from memory - as the manual on php.net states:

The destructor method will be called as soon as all references to a particular object are removed

So what prevents the object from being cleaned up, is the references it has in it to itself. Nice, huh? :)

So, the problem is my object is a memory killer. Unfortunately, I can't think of a solution (other than writing an ugly method which clears the questions and calling that from the loop). The destructor in Survey is not an option; as stated above this is not called because the Question objects still have references.

Any ideas? Someone must have run into this problem already - the parent-containing-child-objects is not an uncommon architecture, is it?

like image 511
Rijk Avatar asked Aug 18 '11 12:08

Rijk


1 Answers

So, here is the answer: switch to PHP 5.3, since this issue have been resolved in it. If you have to work with PHP < 5.3.0, it is your responsibility to free objects captured in circle references. One possible aproach is to introduce special method that will strip off links to child objects to allow them be collected by GC

P.S. also might be useful for somebody, Doctrine 1.2 have such a links in models, so it's subject for memory leaks, especially if you fetch lots of entities from your database. If you are facing this issues, try (1) reduce amount of entities fetched (e.g. hydrate as arrays), (2) process entities with raw sql requests.

like image 198
J0HN Avatar answered Sep 28 '22 15:09

J0HN