¿Por qué no funciona PHP Doctine's free ()?
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
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.