При отладке фрагмента кода, который исчерпал память, я обнаружил очень интересную проблему, и самое главное, я не знаю, как ее исправить.
Приложение состоит примерно из одного 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 не вариант; как указано выше, это не называется , потому что объекты Вопроса по-прежнему имеют ссылки.
Есть идеи? Кто-то, должно быть, уже столкнулся с этой проблемой - родительские объекты-дочерние объекты - это не редкая архитектура, не так ли?