Warum ist PHP Doctine der free () funktioniert nicht?
Frage
Dies ist eine für alle von euch Lehre Benutzer ist da draußen. Ich habe einen PHP CLI-Daemon-Prozess, der eine Tabelle alle n Sekunden prüft Einträge zu finden, die nicht verarbeitet wurden. Es ist im Grunde ein FIFO. Wie auch immer, ich überschreiten die Erinnerung immer zugewiesen becuase Lehre PHP entbindet nicht die Ressourcen. Zur Bekämpfung dieses Problems ist es frei für das Query-Objekt zur Verfügung stellt. Ich kann nicht scheinen, um es aber funktionieren. Hier ist der Code:
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();
Irgendwelche Ideen, was ich tue falsch?
EDIT: Ich bin mit 1.0.3
EDIT: Ich habe alle unten stehenden Vorschläge ausprobiert. Ich war sehr zuversichtlich für unset()
wie ich es dort hatte, bevor ich free()
gefunden.
Hier mehr des Codes ist, um möglicherweise in jeder Hilfe zu unterstützen. Bevor Sie das Öffnen und Schließen der Verbindung in Frage wird es Daemon Prozess sein, der Kinder und ich habe erlebt die Verbindung laicht muss eindeutig sein.
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
Einige Beispielausgabe:
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
Lösung
Das Problem ist, dass free()
nicht die Lehre Objekte aus dem Speicher nicht entfernt, sondern beseitigt nur die zirkulären Verweise auf diesen Objekten, es möglich, dass der Garbage Collector Bereinigungs diese Objekte zu machen. Bitte finden Sie unter 23,6 Freie Objekte in der Lehre Handbuch :
Ab Version 5.2.5, PHP ist nicht in der Lage Objektgraphen zu Müll sammeln, haben zirkuläre Referenzen, z.B. Elternteil hat einen Verweis auf ein Kind, die aufweist Verweis auf Parent. Seit vielen Lehre Modell-Objekte haben eine solche Beziehungen, wird PHP nicht frei, ihre Speicher, auch wenn die Objekte gehen aus Anwendungsbereich.
Für die meisten PHP-Anwendungen, diese Problem ist von geringer Bedeutung, da PHP-Skripte sind in der Regel sein kurzlebig. Langlebigeren Skripte, z.B. Massendaten Importeure und Exporteure können über genügend Arbeitsspeicher ausgeführt es sei denn, Sie manuell den Kreis brechen Referenzketten. Lehre bietet eine free () Funktion auf Doctrine_Record, Doctrine_Collection und Doctrine_Query, die die beseitigt zirkuläre Referenzen auf diese Objekte, befreien sie für Müll up Sammlung.
Die Lösung sollte sein, das unset()
Objekt $query
free()
nach der Verwendung:
$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
Andere Tipps
Doctrine_Query hat auch einen kostenlosen () -Methode, zur Zeit sind Sie gerade telefonieren kostenlos () auf Ihrem Doctrine_Collection, zum Beispiel versuchen:
$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();
Keine Erfahrung mit Lehre (nur ein gewisses Interesse, wie ich es in dieser Woche-Ende entdeckt ...), so nehmen oder meine Vermutung verlassen ... ^ _ ^
Ich würde versuchen, die Erstellung der Abfrage von seinem ausführen Teil trennen:
$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();
Nicht sicher, was zurückkehrt ausführen, aber nur für den Fall, es ist ein Versuch wert ... Es sei denn, jemand einen aufgeklärten Rat hat! :-P
Versuchen $ query-> kostenlos (true);
(?)
Ich glaube, ich könnte nur PDO nicht benutzen will für die Back-End-Teile, die wirklich die ORM sowieso nicht brauchen, da es nicht so viele Abfragen sind. Ich wollte wirklich nur einen einzigen Weg, um mit der DB über alle meine apps in diesem System zu interagieren. Vielleicht werde ich etwas mehr Gedanken.