уничтожение объекта со ссылками на себя - PullRequest
6 голосов
/ 18 августа 2011

При отладке фрагмента кода, который исчерпал память, я обнаружил очень интересную проблему, и самое главное, я не знаю, как ее исправить.

Приложение состоит примерно из одного Survey объекта, который содержит несколько Question объектов. Объекты Вопрос содержат ссылку на опрос, в котором они находятся, это необходимо для возможности получить ответы, например, из других Вопросов.


Следующий цикл вызывал переполнение памяти:

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

Ничего особенного в конструкторе Survey не происходит;

  • извлечение его свойств из базы данных
  • получение свойств всех вопросов из базы данных
  • создание объекта Question для каждого вопроса (передача ссылки на $ this)
  • добавление всех объектов Question во внутренний массив

и, посмотрев на код, вы скажете, что на каждой итерации объект очищается из памяти, поскольку переменная $ Survey перезаписывается. Правильно?? Неправильно:)

Память накапливается, когда скрипт проходит цикл - добавление вызовов memory_get_usage() показывает, что память, используемая объектом Survey, не освобождается должным образом, в настоящий момент другой объект назначен переменной $Survey , Даже вызов unset( $Survey ) в конце цикла не освобождает память.


Виновником являются ссылки на $this, которые передаются объектам Вопроса при создании. Эти ссылки препятствуют удалению объекта из памяти - как говорится в руководстве на php.net:

Метод деструктора будет вызван, как только будут удалены все ссылки на определенный объект

Итак, что мешает очистить объект, так это ссылки на него. Хорошо, а? :)

Итак, проблема в том, что мой объект - убийца памяти. К сожалению, я не могу придумать решение (кроме написания уродливого метода, который очищает вопросы и вызывает его из цикла). Деструктор в Survey не вариант; как указано выше, это не называется , потому что объекты Вопроса по-прежнему имеют ссылки.

Есть идеи? Кто-то, должно быть, уже столкнулся с этой проблемой - родительские объекты-дочерние объекты - это не редкая архитектура, не так ли?

1 Ответ

2 голосов
/ 18 августа 2011

Итак, вот ответ: переключитесь на PHP 5.3, так как эта проблема была решена в нем.Если вам нужно работать с PHP <5.3.0, вы обязаны освободить объекты, захваченные в ссылках круга.Один из возможных подходов - ввести специальный метод, который будет отбирать ссылки на дочерние объекты, чтобы позволить им собираться <code>GC

PS. Также может быть полезным для кого-то, Doctrine 1.2 имеет такие ссылки в моделях,он подвержен утечкам памяти, особенно если вы выбираете много объектов из вашей базы данных.Если вы столкнулись с этой проблемой, попробуйте (1) уменьшить количество извлекаемых сущностей (например, гидрировать как массивы), (2) обработать сущности с необработанными запросами sql.

...