Почему PHP Doctine free () не работает? - PullRequest
5 голосов
/ 17 ноября 2008

Это один для любого из вас, пользователей Doctrine. У меня есть процесс демона PHP CLI, который проверяет таблицу каждые n секунд, чтобы найти записи, которые не были обработаны. Это в основном FIFO. В любом случае, я всегда превышаю объем памяти, выделенной для PHP, потому что Doctrine не освобождает его ресурсы. Для борьбы с этой проблемой предоставляется бесплатный объект запроса. Я не могу заставить его работать, хотя. Вот код:

 22     print "You are using " . (memory_get_usage() / 1024). "\n";
 23     $query = Doctrine_Query::create()
 24                 ->from('SubmissionQueue s')
 25                 ->where('s.time_acted_on IS NULL')
 26                 ->orderby('s.time_queued')
 27                 ->limit(1)
 28                 ->execute();
 29     print $query[0]->time_queued . "\n";
 30     $query->free();

Есть идеи, что я делаю не так?

РЕДАКТИРОВАТЬ: я использую 1.0.3

РЕДАКТИРОВАТЬ: я попробовал все нижеприведенные предложения. Я очень надеялся на unset(), поскольку у меня это было там до того, как я нашел free().

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

  1 <?php
  2
  3 require_once('/usr/local/lib/php/Doctrine/lib/Doctrine.php');
  4
  5 spl_autoload_register(array('Doctrine', 'autoload'));
  6
  7 $manager = Doctrine_Manager::getInstance();
  8 $manager->setAttribute('model_loading','conservative');
  9 Doctrine::loadModels('lib/model/master');
 10
 11 while(1){
 12     print "You are using " . intval(memory_get_usage() / 1024) . "\n";
 13     $manager->connection('********************************************','master');
 14     $query = Doctrine_Query::create()
 15                 ->from('SubmissionQueue s')
 16                 ->where('s.time_acted_on IS NULL')
 17                 ->orderby('s.time_queued')
 18                 ->limit(1)
 19                 ->execute();
 20     print "[" . $query[0]->time_queued . "]\n";
 21     $query->free();
 22     unset($query);
 23     $query = null;
 24     $manager->closeConnection(Doctrine_Manager::getInstance()->getConnection('master'));
 25     sleep(5);
 26 }
 27

Пример вывода:

You are using 14949KB
[2008-11-17 13:59:00]
You are using 14978KB
[2008-11-17 13:59:00]
You are using 15007KB
[2008-11-17 13:59:00]
You are using 15035KB
[2008-11-17 13:59:00]
You are using 15064KB
[2008-11-17 13:59:00]
You are using 15093KB
[2008-11-17 13:59:00]
You are using 15121KB
[2008-11-17 13:59:00]
You are using 15150KB
[2008-11-17 13:59:00]
You are using 15179KB
[2008-11-17 13:59:00]
You are using 15207KB
[2008-11-17 13:59:00]
You are using 15236KB
[2008-11-17 13:59:00]
You are using 15265KB
[2008-11-17 13:59:00]
You are using 15293KB
[2008-11-17 13:59:00]
You are using 15322KB

Ответы [ 5 ]

5 голосов
/ 17 ноября 2008

Проблема в том, что free() не удаляет объекты Doctrine из памяти, а просто удаляет циклические ссылки на эти объекты, позволяя сборщику мусора очищать эти объекты. Пожалуйста, смотрите 23.6 Свободные объекты в Руководстве по доктрине :

Начиная с версии 5.2.5, PHP не может мусора собирать графы объектов, которые иметь круговые ссылки, например родитель имеет ссылку на ребенка, который имеет ссылка на Родителя. Поскольку многие Объекты модели доктрины имеют такие отношения, PHP не освободит их память, даже когда объекты выходят из Объем.

Для большинства приложений PHP это проблема не имеет большого значения, поскольку PHP-скрипты, как правило, кратковременный. Долгоживущие сценарии, например импортеры больших объемов данных и экспортеры могут исчерпать память если вы не разорвете вручную цепочки ссылок. Доктрина обеспечивает функция free () для Doctrine_Record, Doctrine_Collection, и Doctrine_Query, который устраняет циркулярные ссылки на эти объекты, освобождая их от мусора коллекция.

Решение должно быть для unset() объекта $query после использования free():

$query = Doctrine_Query::create()
            ->from('SubmissionQueue s')
            ->where('s.time_acted_on IS NULL')
            ->orderby('s.time_queued')
            ->limit(1);
$query->execute();
print $query[0]->time_queued . "\n";
$query->free();
unset($query); // perhaps $query = null; will also work
1 голос
/ 17 февраля 2009

Doctrine_Query также имеет метод free (), в данный момент вы просто вызываете free () для вашей коллекции Doctrine_Collection, например, попытайтесь:

 $query = Doctrine_Query::create()
             ->from('SubmissionQueue s')
             ->where('s.time_acted_on IS NULL')
             ->orderby('s.time_queued')
             ->limit(1);
 $results = $query->execute();
 print $results[0]->time_queued . "\n";

 $results->free();
 $query->free();
0 голосов
/ 18 ноября 2008

Я думаю, что я мог бы просто использовать PDO для внутренних частей, которые действительно не нуждаются в ORM, так как запросов не так много. Я просто очень хотел иметь единый способ взаимодействия с БД во всех моих приложениях в этой системе. Может быть, я еще подумаю.

0 голосов
/ 17 ноября 2008

Попробуйте $ query-> free (true);

(?)

0 голосов
/ 17 ноября 2008

Нет опыта работы с Доктриной (просто какой-то интерес, как я обнаружил в этот уик-энд ...), поэтому возьмите или оставьте мое предположение ... ^ _ ^

Я бы попытался отделить создание запроса от его исполняемой части:

$query = Doctrine_Query::create()
            ->from('SubmissionQueue s')
            ->where('s.time_acted_on IS NULL')
            ->orderby('s.time_queued')
            ->limit(1);
$query->execute();
print $query[0]->time_queued . "\n";
$query->free();

Не уверен, что execute возвращает, но на всякий случай стоит попробовать ... Если у кого-то нет более просвещенного совета! : -Р

...