#php #orm #symfony1 #doctrine
#php #orm #symfony1 #доктрина
Вопрос:
Я продолжаю получать эту ошибку при запуске одного из моих скриптов;
Фатальная ошибка PHP: разрешенный объем памяти в 1073741824 байта исчерпан (пытался выделить 71 байт) … lib/symfony-1.4.11/lib/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Connection/Statement.php в строке 246, …
Ниже приведена урезанная версия скрипта, который вызывает ошибку;
public function executeImportFile(sfWebRequest $request)
{
ini_set('memory_limit', '1024M');
set_time_limit ( 0 );
//more codes here...
$files = scandir($workspace.'/'.$directory);
foreach ($files as $file) {
$path = $workspace.'/'.$directory.'/'.$file;
if ($file != "." amp;amp; $file != "..") {
$this->importfile($path);
}
}
}
protected function importfile($path){
$connection =
sfContext::getInstance()->getDatabaseManager()->getDatabase('doctrine')->getDoctrineConnection();
$connection->beginTransaction();
try {
//more codes here...
while ($data = $reader->read()) //reads each line of a csv file
{
// send the line to another private function to be processed
// and then write to database
$this->writewave($data);
}
$connection->commit();
} catch (Exception $e) {
$connection->rollback();
}
}
В основном скрипт читает все CSV-файлы в
папка (которая содержит десятки тысяч строк каждая), обработайте ее,
и запишите это в базу данных, используя транзакцию Doctrine.
Хотя я не думаю, что мне нужно устанавливать лимит памяти и ограничение по времени в обеих функциях, скрипт завершается, поскольку Doctrine использует весь выделенный 1 ГБ памяти.
Обычно она останавливается после обработки 10 файлов, а выделение большего объема памяти позволит ей обработать немного больше файлов и все равно приведет к сбою.
Есть ли что-то, чего мне здесь не хватает, из-за чего память не освобождается после обработки каждого файла?
Мохд Шакир Закария http://www.mohdshakir.net
Ответ №1:
Старайтесь освобождать любые объекты везде, где только можете, включая объекты запросов / подключений, особенно когда они находятся внутри циклов.
Комментарии:
1. Спасибо, я попытался освободить объекты, и это решает мою проблему 🙂
2. Кто-нибудь пробовал компилировать Doctrine из Symfony? есть какие-либо указания на такое решение
3. @Prasad Я опаздываю на вечеринку, но я оставлю ответ для дальнейшего использования. В Symfony «unset» не будет работать. Вы должны отсоединить свои сущности от EntityManager с помощью
$em->detach()
, за которой следует$em->clear()
, а затем заставить сборщик мусора PHP работать сgc_enable();
иgc_collect_cycles()
это особенно полезно, когда вы используете doctrine в цикле. Просто будьте осторожны с отображенными и обратными отношениями, потому что использование$em->detach()
или$em->clear()
слишком рано вызовет каскадные проблемы с вашими объектами!
Ответ №2:
Doctrine использует заведомо много памяти при работе с большими наборами данных — импорт больших / множественных файлов таким образом невозможен.
Даже если вы импортируете каждый файл в отдельном вызове функции, doctrine имеет внутренний объектный кэш, поэтому они не освобождаются.
Вашим лучшим вариантом было бы немного изменить задачу, чтобы она принимала filename в качестве параметра. Если она передана, обработайте только этот файл (надеясь, что он не станет слишком большим). Если имя файла не передано, оно перебирает все файлы, как сейчас, и вызывает себя через exec
, так что это другой процесс, и память действительно освобождается.
Комментарии:
1. Я собираюсь сделать что-то похожее на OP — я действительно не вижу необходимости в Doctrine — столкнусь ли я с проблемами при использовании подключения PDO?
2. Нет, у PDO нет объектного кэша, как у doctrine.
3. Спасибо… Так, может быть, это вариант для OP?
4. Зависит от того, нужна ли ему бизнес-логика, содержащаяся в его моделях, определенно нет. В общем, лучшим решением является разные процессы через каждые несколько тысяч записей.
Ответ №3:
самая большая проблема, которую я вижу в вашем скрипте, заключается в том, что вы очень часто вызываете sfcontext. IMHO sfcontext не является синглтоном, что означает, что вы создаете новый экземпляр в каждом цикле. не могли бы вы передать соединение в метод?
public function executeImportFile(sfWebRequest $request)
{
ini_set('memory_limit', '1024M');
set_time_limit ( 0 );
$connection = sfContext::getInstance()->getDatabaseManager()->getDatabase('doctrine')->getDoctrineConnection();
//more codes here...
$files = scandir($workspace.'/'.$directory);
foreach ($files as $file) {
$path = $workspace.'/'.$directory.'/'.$file;
if ($file != "." amp;amp; $file != "..") {
$this->importfile($path, $connection);
}
}
}
protected function importfile($path, $connection){
$connection->beginTransaction();
try {
while ($data = $reader->read()) //reads each line of a csv file
{
$this->writewave($data);
}
$connection->commit();
} catch (Exception $e) {
$connection->rollback();
}
}
Комментарии:
1.
sfContext
является синглтоном, см. Источник sfContext