2010-06-24 17 views
13

Ho uno script PHP eseguito su cron che può richiedere fino a 15 minuti per l'esecuzione. A intervalli regolari ho sputando memory_get_usage() così posso vedere cosa sta succedendo. La prima volta che mi dice che uso sono a 10 mega. Quando finisce la sceneggiatura, sono a 114 mega!garbage collection php durante lo script in esecuzione

PHP fa la garbage collection mentre lo script è in esecuzione? O cosa sta succedendo a tutta quella memoria? C'è qualcosa che posso fare per forzare la garbage collection. Il compito che sta facendo il mio script è un'importazione notturna di un paio di migliaia di nodi in Drupal. Quindi sta facendo la stessa cosa un sacco di volte.

Qualche suggerimento?

risposta

16

La chiave è che si unset le variabili globali non appena non ne hai bisogno.

Non è necessario chiamare unset in modo esplicito per le variabili locali e le proprietà dell'oggetto perché queste vengono distrutte quando la funzione esce dall'ambito o l'oggetto viene distrutto.

PHP mantiene un conteggio di riferimento per tutte le variabili e le distrugge (nella maggior parte delle condizioni) non appena questo conteggio dei riferimenti passa a zero. Gli oggetti hanno un conteggio di riferimento interno e le variabili stesse (i riferimenti all'oggetto) hanno ciascuno un conteggio di riferimenti. Quando tutti i riferimenti agli oggetti sono stati distrutti perché i loro coutn di riferimento hanno raggiunto 0, l'oggetto stesso verrà distrutto. Esempio:

$a = new stdclass; //$a zval refcount 1, object refcount 1 
$b = $a;   //$a/$b zval refcount 2, object refcount 1 
//this forces the zval separation because $b isn't part of the reference set: 
$c = &$a;   //$a/$c zval refcount 2 (isref), $b 1, object refcount 2 
unset($c);   //$a zval refcount 1, $b 1, object refcount 2 
unset($a);   //$b refcount 1, object refcount 1 
unset($b);   //everything is destroyed 

Ma consideri il seguente scenario:

class A { 
    public $b; 
} 
class B { 
    public $a; 
} 

$a = new A; 
$b = new B; 
$a->b = $b; 
$b->a = $a; 
unset($a); //cannot destroy object $a because $b still references it 
unset($b); //cannot destroy object $b because $a still references it 

Questi riferimenti ciclici sono dove PHP 5.3 di calci garbage collector in È possibile richiamare esplicitamente il garbage collector con gc_collect_cycles..

Vedere anche Reference Counting Basics e Collecting Cycles nel manuale.

2

Utilizzare unset() il più possibile, controllare la memoria utilizzata più spesso. sì, php esegue la garbage collection durante il runtime in alcune condizioni. ecco un utile post su php.net.

1

Se la memoria aumenta di molto, probabilmente non la rilascerai. Hai creato una perdita di memoria. La raccolta dei dati inutili non ti aiuterà se non annulli variabili, distruggi oggetti e/o essi escono dal campo di applicazione.

Stai cancellando i nodi che carichi una volta che hai finito con loro? Ho scritto script PHP che funzionano per ore, elaborando milioni di record di database, senza problemi e l'utilizzo della memoria che va su e giù in un intervallo molto accettabile.

3

PHP garbage collection è in gran parte un contatore di riferimento (ha qualche rilevamento del ciclo). Se si mantengono riferimenti che sono ancora accessibili intorno a questi si sommano facilmente se non vengono liberati.

Utilizzare unset() per liberare variabili che non si utilizzano più. Se semplicemente sovrascrivi le variabili (ad esempio, con null) questo consentirà al GC di ridurre la quantità di spazio richiesta da tale variabile, ma non tanto quanto unset che consente effettivamente la distruzione del valore di riferimento.

Si dovrebbero inoltre rilasciare correttamente tutte le risorse ecc. Che si utilizzano.

Si vedrà ancora un aumento di memoria durante il runtime poiché il GC è libero di rilasciarlo nella propria disconnessione, ad esempio quando ci sono cicli cpu gratuiti o quando inizia a esaurirsi nella memoria.