2009-02-09 13 views
5

Si utilizo una estructura en árbol de nodos similar al siguiente código, ¿tengo que preocuparme por la referencia circular?
He leído que PHP utiliza un mecanismo de asignación de memoria que puede hacer la vida muy difícil para el recolector de basura cuando hay referencias circulares involucradas.¿Cuál es la escala del problema de referencia circular de PHP y debería preocuparme por ello?

Lo que quiero saber es:

  • Si mi árbol consta de sólo unos pocos nodos, digamos 25, es esto un problema?
  • ¿Se liberará la memoria al final de la secuencia de comandos o crearé lentamente un problema para el servidor?
  • ¿En qué circunstancias tendrá este problema un efecto durante la ejecución del script?
  • ¿La destrucción manual de las referencias resolverá el problema y debería hacerlo siempre?
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

Creo que esto debería estar bien. AFAIK, así es como funciona la implementación PHP DOM. –

Respuesta

4

Punto por punto:

  • Si mi árbol consta de sólo unos pocos nodos, digamos 25, es esto un problema?

No, a menos que sus nodos sean verdaderos monstruos.

  • ¿La memoria de ser liberados al final de la secuencia de comandos o estoy poco a poco creando un problema para el servidor?

Cuando el intérprete se apaga, se libera toda la memoria.

  • ¿En qué circunstancias será este problema tener un efecto durante la ejecución del script?

dudo que tendrá nada de qué preocuparse a menos que tenga límites de memoria muy bajos o muy grandes estructuras de datos dinámicos.Si tiene 25 nodos que no se crean/liberan con frecuencia, no tendrá problemas.

  • Will destruir manualmente las referencias a resolver el problema y deben siempre hacerlo?

Esto ayudará. Cuando cargamos un gran conjunto de datos en nuestra base de datos con Propel nos topamos con un gran problema con el consumo de memoria que rastreamos a las referencias circulares que no se liberan. Nuestra solución fue llamar a un método que borró todas las referencias.

+0

¿Cómo se creó este método? Me estoy encontrando con el mismo problema con mi propio ORM. – andho

+0

Solo teniendo problemas en las pruebas, porque de lo contrario los scripts no son tan largos. – andho

+0

Desafortunadamente, hace mucho tiempo que no trabajo en Propel y ya no tengo acceso al código. Lo siento, andho. – sig11

3

Tal vez sea así, pero ya que lanza hacia fuera todos los objetos al final de cada solicitud (a menos que el almacenamiento en caché), no creo que muchos programadores de PHP se preocupan por esto.

Si está escribiendo scripts de línea de comandos en PHP, entonces quizás tenga que preocuparse por ello, pero tendría que estar escribiendo un código PHP complicado antes de que se convierta en algo que valga la pena preocuparse. Y si ese es el caso, tienes problemas mayores.

Buena suerte.

+0

Además, está el método __destruct(). –

2

Dada la naturaleza de la mayoría de las páginas PHP, es decir, el proceso se ejecuta para una página web y se descarta al finalizar, dudo que sea un problema. No he visto problemas con referencias circulares antes y los he usado sin problemas. En mi experiencia, se encontrará con más problemas con el simple consumo de memoria, pero PHP 5 lo ha mitigado un tanto al dejar de copiar objetos y matrices, a menos que se le indique lo contrario.

2

PHP 5.3 incluirá funciones de destrucción y detección de referencias circulares. Es una configuración opcional, y solo debe usarse cuando sea necesario porque el recolector de basura tendrá un impacto en el rendimiento, pero está hecho a medida para su ejemplo.

Desarrolle ahora, tome precauciones para desreferencia explícita en un método __destruct(), y actualice a 5.3 cuando sea posible.

+3

Por lo que recuerdo (antes de php5.3) __destruct solo se llama cuando no hay referencias al objeto que queda. Por lo tanto, __destruct debería llamarse explícitamente si es parte de una referencia circular. – dsas

+0

Se llamará al '__destruct' como parte de la' secuencia de cierre' al final del script en PHP 5.3. Sin embargo, en ese caso, la secuencia de llamada es aleatoria (es decir, el '__destruct' se puede llamar mientras que otros objetos todavía tienen referencias a dicho objeto). –

Cuestiones relacionadas