Limpieza de Ciclos
   
    Tradicionalmente, los mecanismos de conteo de referencias, como los utilizados anteriormente
    en PHP, no saben manejar las fugas de memoria debidas a referencias circulares;
    sin embargo, desde PHP 5.3.0, un algoritmo síncrono derivado del análisis
    » Concurrent Cycle Collection in Reference Counted Systems
    se utiliza para abordar este problema en particular.
   
   
    Una explicación completa del funcionamiento del algoritmo iría un poco más allá del alcance de esta sección,
    pero aquí presentaremos los principios básicos. En primer lugar, estableceremos algunas reglas básicas.
    Si un refcount se incrementa, el contenedor siempre se utiliza, por lo tanto, no se limpia. Si el refcount
    se decrementa y llega a cero, el contenedor zval puede ser eliminado y la memoria liberada. En primer lugar, esto significa
    que los ciclos perturbadores solo pueden crearse cuando el refcount se decrementa a un valor
    diferente de cero. Luego, en un ciclo problemático, es posible detectar la basura verificando si es posible o no
    decrementar su refcount en uno, verificando luego qué zvals tienen un refcount a cero.
   
   
     
   
   
    Para evitar tener que llamar a la rutina de limpieza en cada decrementación de refcount posible,
    el algoritmo coloca todas las raíces zval en un "búfer de raíces" (marcándolas en "violeta").
    También se asegura de que cada raíz aparezca solo una vez en el búfer.
    El mecanismo de limpieza solo interviene cuando el búfer está lleno. Vea el paso A
    en la figura anterior.
   
   
    En el paso B, el algoritmo lanza una búsqueda en todas las raíces posibles, para
    decrementar en una unidad los refcounts de todas las zvals que encuentra, teniendo mucho
    cuidado de no decrementar dos veces el refcount de la misma zval (marcándolas
    como "grises"). En el paso C, el algoritmo relanza una búsqueda en todas las raíces
    posibles y escanea el valor de refcount de cada zval. Si encuentra un refcount a cero,
    la zval se marca como "blanca" (azul en la figura). Si encuentra un valor superior a cero,
    cancela la decrementación del refcount realizando una búsqueda desde este nodo, y las
    marca como "negras" nuevamente. En el último paso, D, el algoritmo recorre todo el
    búfer de raíces y las elimina, escaneando cada zval; cualquier zval marcada como "blanca" en el
    paso anterior será entonces eliminada de la memoria.
   
   
    Ahora que se sabe globalmente cómo funciona el algoritmo, se verá cómo se ha integrado en PHP. Por omisión, el recolector de basura de PHP está
    activado. Sin embargo, hay una opción de php.ini para cambiar esto:
    zend.enable_gc.
   
   
    Cuando el recolector de basura está activado, el algoritmo de búsqueda de ciclos
    descrito anteriormente se ejecuta cada vez que el búfer está lleno. El búfer de
    raíces tiene un tamaño fijado a 10.000 raíces (este parámetro es modificable gracias a
    GC_THRESHOLD_DEFAULT en Zend/zend_gc.c
    en el código fuente de PHP, por lo tanto, se necesita una recompilación). Si el recolector de
    basura está desactivado, la búsqueda de ciclos también lo está. Sin embargo, las raíces
    posibles siempre se registrarán en el búfer, esto no depende de la activación
    del recolector de basura.
   
   
    Si el búfer está lleno mientras el mecanismo de limpieza está desactivado, las raíces
    ya no se registrarán. Estas raíces nunca serán analizadas por el algoritmo, y si
    formaban parte de referencias circulares, nunca se limpiarán, y causarán fugas de memoria.
   
   
    La razón por la que las raíces posibles se registran en el búfer
    incluso si el mecanismo está desactivado es que habría sido demasiado costoso verificar la posible
    activación del mecanismo en cada intento de agregar una raíz al búfer. El mecanismo
    de recolección de basura y análisis puede, por su parte, ser muy costoso en tiempo.
   
   
    Además de poder cambiar el valor del parámetro de configuración
    zend.enable_gc, también se puede activar o desactivar el mecanismo de
    recolección de basura llamando a las funciones gc_enable() o
    gc_disable() respectivamente. Utilizar estas funciones tendrá el mismo efecto que modificar el parámetro de configuración. También se tiene la posibilidad de forzar la ejecución del
    recolector de basura en un momento dado en el script, incluso si el búfer aún no
    está completamente lleno. Para ello, utilice la función gc_collect_cycles(),
    que devolverá el número de ciclos recolectados.
   
   
    Se puede tomar el control desactivando el recolector de basura o forzándolo a pasar en un momento dado porque algunas partes de la aplicación
    podrían depender fuertemente del tiempo de procesamiento, en cuyo caso se podría desear que el recolector de basura no se inicie. Por supuesto, al desactivar el recolector de basura para algunas partes de la aplicación, se corre el riesgo de crear
    fugas de memoria, ya que algunas raíces probables podrían no registrarse en el búfer de memoria de tamaño limitado.
    En consecuencia, generalmente se recomienda desencadenar manualmente el proceso gracias a
    gc_collect_cycles() justo antes de la llamada a
    gc_disable(), para liberar memoria. Esto dejará un búfer
    vacío, y habrá más espacio para raíces probables cuando
    el mecanismo esté desactivado.