yiiext / nested-set-behavior

AR models behavior that allows to work with nested sets tree.
http://www.yiiframework.com/extension/nestedsetbehavior/
BSD 3-Clause "New" or "Revised" License
157 stars 64 forks source link

$_cache variable significantly increases memory usage #25

Closed pohnean closed 10 years ago

pohnean commented 11 years ago

I'm having a huge memory leak issue when iterating through large numbers of ActiveRecords with NestedSetBehavior attached. This is because of the circular reference that is created behaviors are added to ActiveRecord (see https://github.com/yiisoft/yii/issues/1329).

To test this issue:

Create 500 objects with NestedSetBehavior attached and log the memory usage before and after.

$max = 500;

for ($i = 0; $i< $max; $i++) {
    $model = new Model();
 }

The results:

I found out that the $_cache variable used in the afterConstruct() and afterFind() methods were causing a huge increase in memory usage and are not released even after unsetting $model due to circular referencing.

Solution:

  1. Add this function to NestedSetBehavior: public function detach($owner) { // free up memory when detachBehavior() is called. self::$_cached = null; self::$_c = null;

       parent::detach($owner);

    }

  2. Call $model->detachBehaviors(); Results: Before: 8.75MB After: 12MB
creocoder commented 11 years ago

I think we will solve issue by other (__destructor()) way. Thanks for catch.

pohnean commented 11 years ago

unfortunately __destruct() is only called when the script ends. Thus PHP's garbage collection is not triggered to free up the memory. the only way is to manually remove the circular reference by calling detachBehavior().

creocoder commented 11 years ago

Yes. But i'm against to override detach(). Framework should call destructor on detachBehavior() if behavior have it. So its framework issue. Working on this.

cebe commented 11 years ago

Working on this.

@creocoder what are you trying to do about it? PHP should be aware of cycle references but as mentioned in https://github.com/yiisoft/yii/issues/1329#issuecomment-18729026 there seems to be a bug in php.

creocoder commented 11 years ago

@cebe So solution is:

foreach ($models as $model) {
    $model->detachBehaviors();
}
gc_collect_cycles();

? And we should not do anything?