утечка памяти php / symfony / doctrine?

У меня возникают проблемы с пакетной вставкой объектов в базу данных с использованием symfony 1.4 и doctrine 1.2.

У моей модели есть определенный объект, называемый «Сектор», каждый из которых имеет несколько объектов типа «Купо» (обычно от 50 до 200000). Эти объекты довольно малы; просто короткая строка идентификатора и один или два целых числа. Всякий раз, когда группа Секторов создается пользователем, мне нужно автоматически добавлять все эти экземпляры «Cupo» в базу данных. Если что-то пойдет не так, я использую транзакцию доктрины, чтобы откатить все. Проблема в том, что я могу создать только около 2000 экземпляров, прежде чем у php закончится нехватка памяти. В настоящее время он имеет предел в 128 МБ, которого должно быть более чем достаточно для обработки объектов, которые используют менее 100 байт. Я попытался увеличить лимит памяти до 512 МБ, но php все еще падает, и это не решает проблему. Правильно ли я делаю пакетную вставку или есть лучший способ?

Вот ошибка:

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 71 bytes) in /Users/yo/Sites/grifoo/lib/vendor/symfony/lib/log/sfVarLogger.class.php on line 170 

И вот код:

 public function save($conn=null){ $conn=$conn?$conn:Doctrine_Manager::connection(); $conn->beginTransaction(); try { $evento=$this->object; foreach($evento->getSectores() as $s){ for($j=0;$j<$s->getCapacity();$j++){ $cupo=new Cupo(); $cupo->setActivo($s->getActivo()); $cupo->setEventoId($s->getEventoId()); $cupo->setNombre($j); $cupo->setSector($s); $cupo->save(); } } $conn->commit(); return; } catch (Exception $e) { $conn->rollback(); throw $e; } 

Еще раз, этот код работает отлично для менее 1000 объектов, но ничего больше 1500 терпит неудачу. Спасибо за помощь.

Related of "утечка памяти php / symfony / doctrine?"

Пробовал делать

 $cupo->save(); $cupo->free(); $cupo = null; 

(Но подставляя мой код) И я все еще получаю переполнение памяти. Любые другие идеи, ТАК?

Обновить:

Я создал новую среду в моих базах данных.yml, которая выглядит так:

 all: doctrine: class: sfDoctrineDatabase param: dsn: 'mysql:host=localhost;dbname=.......' username: ..... password: ..... profiler: false 

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

Обновление 2

я добавил

 Doctrine_Manager::connection()->setAttribute(Doctrine_Core::ATTR_AUTO_FREE_QUERY_OBJECTS, true ); 

перед запуском моих запросов и изменением

 $cupo = null; 

в

 unset($cupo); 

И теперь мой сценарий с радостью отбивается. Я уверен, что на этот раз он закончит, не закончив RAM.

Обновление 3

Ага. Это выигрышная комбинация.

Я только что «демоннизировал» скрипт с symfony 1.4 и установил следующее:

 sfConfig::set('sf_debug', false); 

Для задачи symfony я также столкнулся с этой проблемой и сделал следующее. Это сработало для меня.

  • Отключить режим отладки. Добавьте следующее, чтобы инициализировать соединение db

     sfConfig::set('sf_debug', false); 
  • Установить бесплатный атрибут объекта запроса для соединения db

     $connection->setAttribute(Doctrine_Core::ATTR_AUTO_FREE_QUERY_OBJECTS, true ); 
  • Освободите весь объект после использования

     $object_name->free() 
  • Сбросить все массивы после использования unset($array_name)

  • Проверьте все запросы доктрины, используемые в задаче. Освободите все запросы после использования. $q->free() (Это хорошая практика для любого использования запроса).

Это все. Надеюсь, это может помочь кому-то.

Утечка просачивается, и вы не можете с этим поделать. Убедитесь, что вы используете $ q-> free (), когда это применимо, чтобы минимизировать эффект. Доктрина не предназначена для сценариев обслуживания. Единственный способ обойти эту проблему – разбить скрипт на части, которые будут выполнять часть задачи. Один из способов сделать это – добавить начальный параметр к вашему сценарию и после того, как определенное количество объектов было обработано, сценарий перенаправляет себя с более высоким стартовым значением. Это хорошо работает для меня, хотя это делает письменные сценарии обслуживания более громоздкими.

Попробуйте unset($cupo); после каждой экономии. Это должна быть помощь. Другое дело – разбить скрипт и выполнить пакетную обработку.

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

 $cupo->save(); $cupo->free(); //this call 

как описано в руководстве Doctrine.

Для меня я только что инициализировал задачу:

 // initialize the database connection $databaseManager = new sfDatabaseManager($this->configuration); $connection = $databaseManager->getDatabase($options['connection'])->getConnection(); $config = ProjectConfiguration::getApplicationConfiguration('frontend', 'prod', true); sfContext::createInstance($config); 

(С PROD CONFIG)
и используйте free () после сохранения () объекта доктрины

память стабильна при 25Mo

 memory_get_usage=26.884071350098Mo 

с php 5.3 на debian squeeze

Периодически закрывайте и повторно открывайте соединение – не уверен, почему, но, похоже, PDO сохраняет ссылки.

То, что работает для меня, вызывает free метод следующим образом:

 $cupo->save(); $cupo->free(true); // free also the related components unset($cupo);