Pregunta

Este es uno para cualquiera de ustedes, usuarios de Doctrine. Tengo un proceso de demonio CLI de PHP que verifica una tabla cada n segundos para encontrar entradas que no se han procesado. Básicamente es un FIFO. De todos modos, siempre excedo la memoria asignada a PHP porque Doctrine no libera sus recursos. Para combatir este problema, proporciona gratuitamente el objeto de consulta. Aunque parece que no puedo hacer que funcione. Aquí está el código:

 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();

¿Alguna idea de lo que estoy haciendo mal?

EDITAR: estoy usando 1.0.3

EDITAR: he probado todas las sugerencias a continuación. Tenía muchas esperanzas para unset () ya que lo tenía allí antes de encontrar free () .

Aquí hay más del código para posiblemente ayudar en cualquier ayuda. Antes de cuestionar la apertura y el cierre de la conexión, será un proceso demonio que generará niños y, desde mi experiencia, la conexión debe ser única.

  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

Algunos resultados de muestra:

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
¿Fue útil?

Solución

El problema es que free () no elimina los objetos de Doctrine de la memoria, sino que simplemente elimina las referencias circulares en esos objetos, haciendo posible que el recolector de basura limpie esos objetos. Consulte 23.6 Objetos libres en el Manual de doctrina :

  

A partir de la versión 5.2.5, PHP no puede   para recolectar basura objetos gráficos que   tener referencias circulares, p. Padre   tiene una referencia a Child que tiene un   referencia a los padres. Ya que muchos   objetos modelo de doctrina tienen tal   relaciones, PHP no liberará su   memoria incluso cuando los objetos salen de   alcance.

     

Para la mayoría de las aplicaciones PHP, esto   el problema es de poca consecuencia,   ya que los scripts PHP tienden a ser   efímero. Guiones más longevos,   p.ej. importadores de datos a granel y   exportadores, pueden quedarse sin memoria   a menos que rompas manualmente la circular   cadenas de referencia. Doctrine proporciona un   función free () en Doctrine_Record,   Doctrine_Collection, y   Doctrine_Query que elimina el   referencias circulares sobre esos objetos,   liberándolos para la basura   colección.

La solución debe ser unset () el objeto $ query después de usar 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

Otros consejos

Doctrine_Query también tiene un método free (), en este momento solo está llamando a free () en su Doctrine_Collection, por ejemplo, intente:

 $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();

Sin experiencia con Doctrine (solo algo de interés como lo descubrí este fin de semana ...), así que toma o deja mi conjetura ... ^ _ ^

Intentaría separar la creación de la consulta de su parte de ejecución:

$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();

No estoy seguro de qué ejecución regresa, pero por si acaso, vale la pena intentarlo ... ¡A menos que alguien tenga un consejo más inteligente! :-P

Pruebe $ query- > gratis (verdadero);

(?)

Creo que podría usar PDO para las partes de back-end que realmente no necesitan el ORM de todos modos ya que no hay tantas consultas. Realmente quería tener una única forma de interactuar con la base de datos en todas mis aplicaciones en este sistema. Tal vez pensaré un poco más.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top