2009-02-09 10 views
5

Se utilizzo una struttura ad albero di nodi simile al seguente, devo preoccuparmi del riferimento circolare?
Ho letto che PHP utilizza un meccanismo di allocazione della memoria che può rendere la vita molto difficile per il garbage collector quando ci sono riferimenti circolari coinvolti.Qual è la scala del problema di riferimento circolare di PHP e dovrei preoccuparmene?

Quello che voglio sapere è:

  • Se il mio albero è costituito da pochi nodi, diciamo 25, è un problema?
  • La memoria verrà liberata alla fine dello script o sto lentamente creando un problema per il server?
  • In quali circostanze questo problema avrà un effetto durante l'esecuzione dello script?
  • Distruggerà manualmente i riferimenti per risolvere il problema e dovrei farlo sempre?
class Node { 
    private $parent; 
    private $children; 

    function addChild(Node $child) { 
     $this->children[] = $child; 
     $child->setParent($this); 
    } 

    function setParent($parent) { 
     $this->parent = $parent; 
    } 
} 

//eg 
$node0 = new Node; 
$node1 = new Node; 

// nodes 1 and 2 have a circular reference to each other 
$node0->addChild($node1); 
+0

Penso che questo dovrebbe andare bene. AFAIK, questo è il modo in cui funziona l'implementazione del DOM PHP. –

risposta

4

Punto per punto:

  • Se il mio albero è costituito da pochi nodi, diciamo 25, è un problema?

A meno che i nodi non siano veri mostri.

  • Intende la memoria di essere liberati alla fine dello script o sto lentamente creando un problema per il server?

Quando l'interprete si spegne, viene rilasciata tutta la memoria.

  • In quali circostanze questo problema avere un effetto durante l'esecuzione dello script?

dubito avrete nulla di cui preoccuparsi se non si ha limiti di memoria molto basso o molto grandi strutture dati dinamiche.Se si dispone di 25 nodi che non vengono creati/liberati frequentemente, non si verificherà alcun problema.

  • Sarà distruggere manualmente i riferimenti a risolvere il problema e dovrebbero sempre farlo?

Aiuterà. Durante il caricamento di un set di dati di grandi dimensioni nel nostro database con Propel abbiamo riscontrato un sacco di problemi con il consumo di memoria che abbiamo rintracciato su riferimenti circolari non liberati. La nostra soluzione era di chiamare un metodo che cancellasse tutti i riferimenti.

+0

Come hai creato questo metodo. Sto incontrando lo stesso problema con il mio ORM. – andho

+0

Solo problemi nel test, perché altrimenti gli script non sono così lunghi. – andho

+0

Sfortunatamente è passato molto tempo da quando ho lavorato su Propel e non ho più accesso al codice. Mi dispiace, eho. – sig11

3

Forse sì, ma dal momento che butta fuori tutti gli oggetti alla fine di ogni richiesta (a meno che non si sta caching), non credo che molti programmatori PHP preoccuparsi di questo.

Se stai scrivendo script a riga di comando in PHP, allora forse hai un motivo per preoccupartene, ma dovresti scrivere un codice PHP piuttosto complicato prima che diventi qualcosa di cui preoccuparsi. E se questo è il caso, hai problemi più grandi.

Buona fortuna.

+0

Inoltre, esiste il metodo __destruct(). –

2

Data la natura della maggior parte delle pagine PHP, vale a dire che il processo viene eseguito per una pagina Web e viene eliminato al termine, dubito che questo sia un problema. Non ho mai visto problemi con i riferimenti circolari e li ho usati senza problemi. Nella mia esperienza, si incontreranno più problemi con il mero consumo di memoria, ma PHP 5 lo ha mitigato in qualche modo spostandosi dalla semplice copia di oggetti e array a meno che non sia stato detto altrimenti.

2

PHP 5.3 includerà funzionalità di rilevamento e distruzione di riferimento circolare. È un'impostazione facoltativa e dovrebbe essere utilizzata solo quando necessario perché il garbage collector subirà un calo di prestazioni, ma è fatto su misura per il tuo esempio.

Sviluppare ora, prendere precauzioni per il dereferenziamento esplicito in un metodo __destruct() e aggiornare a 5.3 quando possibile.

+3

Per quanto ricordo (prima di php5.3) __destruct viene chiamato solo quando non ci sono riferimenti all'oggetto rimasto. Pertanto __destruct dovrebbe essere chiamato esplicitamente se fa parte di un riferimento circolare. – dsas

+0

Il '__destruct' sarà chiamato come parte della' sequenza di spegnimento' alla fine dello script in PHP 5.3. Tuttavia, in questo caso la sequenza chiamante è casuale (ovvero, il '__destruct' può essere chiamato mentre altri oggetti hanno ancora riferimenti a detto oggetto). –