<?php
include_once $_SERVER['DOCUMENT_ROOT'] . '/include/shared-manual.inc';
$TOC = array();
$TOC_DEPRECATED = array();
$PARENTS = array();
include_once dirname(__FILE__) ."/toc/features.gc.inc";
$setup = array (
  'home' => 
  array (
    0 => 'index.php',
    1 => 'PHP Manual',
  ),
  'head' => 
  array (
    0 => 'UTF-8',
    1 => 'es',
  ),
  'this' => 
  array (
    0 => 'features.gc.refcounting-basics.php',
    1 => 'Bases sobre el conteo de referencias',
    2 => 'Bases sobre el conteo de referencias',
  ),
  'up' => 
  array (
    0 => 'features.gc.php',
    1 => 'Recolecci&oacute;n de basura (Garbage Collection)',
  ),
  'prev' => 
  array (
    0 => 'features.gc.php',
    1 => 'Recolecci&oacute;n de basura (Garbage Collection)',
  ),
  'next' => 
  array (
    0 => 'features.gc.collecting-cycles.php',
    1 => 'Limpieza de Ciclos',
  ),
  'alternatives' => 
  array (
  ),
  'source' => 
  array (
    'lang' => 'es',
    'path' => 'features/gc.xml',
  ),
  'history' => 
  array (
  ),
);
$setup["toc"] = $TOC;
$setup["toc_deprecated"] = $TOC_DEPRECATED;
$setup["parents"] = $PARENTS;
manual_setup($setup);

contributors($setup);

?>
<div id="features.gc.refcounting-basics" class="sect1">
   <h2 class="title">Bases sobre el conteo de referencias</h2>
   <p class="para">
    Una variable PHP se almacena internamente en un contenedor llamado &quot;zval&quot;. Un contenedor
    zval contiene, además del tipo de la variable y su valor, dos informaciones adicionales.
    La primera se llama &quot;is_ref&quot; y es un valor booléano que indica si
    una variable forma parte de una referencia o no. Gracias a esta información, el motor de
    PHP sabe diferenciar las variables normales de las referencias. Como PHP permite
    al programador utilizar referencias, mediante el operador &amp;, un contenedor
    zval posee también un mecanismo de conteo de referencias para optimizar el uso
    de la memoria. Esta segunda información, llamada &quot;refcount&quot;, contiene el número de
    variables (también llamadas símbolos) que apuntan a este contenedor zval. Todos los símbolos
    se almacenan en una tabla de símbolos, y hay una tabla por ámbito de visibilidad
    (scope). Hay un ámbito global para el script principal (el que se llama, por ejemplo, a través
    del navegador) y un ámbito por función o método.
   </p>
   <p class="para">
    Un contenedor zval se crea cuando se crea una nueva variable con un valor
    constante, como por ejemplo:
    <div class="example" id="example-1">
     <p><strong>Ejemplo #1 Creación de un nuevo contenedor zval</strong></p>
     <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br />$a </span><span style="color: #007700">= </span><span style="color: #DD0000">"new string"</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
     </div>

    </div>
   </p>
   <p class="para">
    En este caso, el nuevo símbolo <code class="literal">a</code> se crea en el ámbito global,
    y se crea un nuevo contenedor con el tipo <span class="type"><a href="language.types.string.php" class="type string">string</a></span> y el valor
    <code class="literal">new string</code>. El bit &quot;is_ref&quot; se establece por omisión en <strong><code><a href="reserved.constants.php#constant.false">false</a></code></strong> ya que ninguna
    referencia ha sido creada por el programador. El contador de referencias &quot;refcount&quot; se establece en
    <code class="literal">1</code> ya que solo hay un símbolo que utiliza este contenedor.
    Es de destacar que las referencias (es decir, &quot;is_ref&quot; es <strong><code><a href="reserved.constants.php#constant.true">true</a></code></strong>) con &quot;refcount&quot;
    <code class="literal">1</code>, se tratan como si no fueran
    referencias (es decir, como si &quot;is_ref&quot; fuera <strong><code><a href="reserved.constants.php#constant.false">false</a></code></strong>). Si ha
    instalado <a href="http://xdebug.org/" class="link external">&raquo;&nbsp;Xdebug</a>, puede mostrar esta
    información llamando a <span class="function"><strong>xdebug_debug_zval()</strong></span>.
   </p>
   <p class="para">
    <div class="example" id="example-2">
     <p><strong>Ejemplo #2 Mostrar información zval</strong></p>
     <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br />$a </span><span style="color: #007700">= </span><span style="color: #DD0000">"new string"</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">xdebug_debug_zval</span><span style="color: #007700">(</span><span style="color: #DD0000">'a'</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
     </div>

     <div class="example-contents"><p>El ejemplo anterior mostrará:</p></div>
     <div class="example-contents screen">
<div class="cdata"><pre>
a: (refcount=1, is_ref=0)=&#039;new string&#039;
</pre></div>
     </div>
    </div>
   </p>
   <p class="para">
    Asignar esta variable a otro símbolo incrementará el refcount.
   </p>
   <p class="para">
    <div class="example" id="example-3">
     <p><strong>Ejemplo #3 Incrementar el refcount de una zval</strong></p>
     <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br />$a </span><span style="color: #007700">= </span><span style="color: #DD0000">"new string"</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">$b </span><span style="color: #007700">= </span><span style="color: #0000BB">$a</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">xdebug_debug_zval</span><span style="color: #007700">( </span><span style="color: #DD0000">'a' </span><span style="color: #007700">);<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
     </div>

     <div class="example-contents"><p>El ejemplo anterior mostrará:</p></div>
     <div class="example-contents screen">
<div class="cdata"><pre>
a: (refcount=2, is_ref=0)=&#039;new string&#039;
</pre></div>
     </div>
    </div>
   </p>
   <p class="para">
    El refcount vale <code class="literal">2</code> aquí, ya que el mismo contenedor está ligado
    tanto a <var class="varname">a</var> como a <var class="varname">b</var>. PHP es lo suficientemente
    inteligente como para no duplicar el contenedor cuando no es necesario.
    Los contenedores se destruyen cuando su &quot;refcount&quot; llega a cero. El
    &quot;refcount&quot; se decrementa en uno cuando cualquier símbolo ligado a
    un contenedor sale del ámbito (por ejemplo: cuando la función termina) o
    cuando un símbolo se desasigna (por ejemplo: por la llamada a <span class="function"><a href="function.unset.php" class="function">unset()</a></span>).
    El siguiente ejemplo lo demuestra:
   </p>
   <p class="para">
    <div class="example" id="example-4">
     <p><strong>Ejemplo #4 Decrementar el refcount de una zval</strong></p>
     <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br />$a </span><span style="color: #007700">= </span><span style="color: #DD0000">"new string"</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">$c </span><span style="color: #007700">= </span><span style="color: #0000BB">$b </span><span style="color: #007700">= </span><span style="color: #0000BB">$a</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">xdebug_debug_zval</span><span style="color: #007700">( </span><span style="color: #DD0000">'a' </span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$b </span><span style="color: #007700">= </span><span style="color: #0000BB">42</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">xdebug_debug_zval</span><span style="color: #007700">( </span><span style="color: #DD0000">'a' </span><span style="color: #007700">);<br />unset( </span><span style="color: #0000BB">$c </span><span style="color: #007700">);<br /></span><span style="color: #0000BB">xdebug_debug_zval</span><span style="color: #007700">( </span><span style="color: #DD0000">'a' </span><span style="color: #007700">);<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
     </div>

     <div class="example-contents"><p>El ejemplo anterior mostrará:</p></div>
     <div class="example-contents screen">
<div class="cdata"><pre>
a: (refcount=3, is_ref=0)=&#039;new string&#039;
a: (refcount=2, is_ref=0)=&#039;new string&#039;
a: (refcount=1, is_ref=0)=&#039;new string&#039;
</pre></div>
     </div>
    </div>
   </p>
   <p class="para">
    Si ahora se llama a <code class="literal">unset($a);</code>, el contenedor zval, incluyendo
    el tipo y el valor, será eliminado de la memoria.
   </p>

   <div class="sect2" id="features.gc.compound-types">
    <h3 class="title">Tipos compuestos</h3>

    <p class="para">
     Las cosas se complican en el caso de tipos compuestos como <span class="type"><a href="language.types.array.php" class="type array">array</a></span> y
     <span class="type"><a href="language.types.object.php" class="type object">object</a></span>. A diferencia de los valores escalares, los
     <span class="type"><a href="language.types.array.php" class="type array">array</a></span> y <span class="type"><a href="language.types.object.php" class="type object">object</a></span> almacenan sus propiedades en una tabla de
     símbolos que les es propia. Esto significa que el siguiente ejemplo crea tres contenedores
     zval:
    </p>
    <p class="para">
     <div class="example" id="example-5">
      <p><strong>Ejemplo #5 Creación de una zval <span class="type"><a href="language.types.array.php" class="type array">array</a></span></strong></p>
      <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br />$a </span><span style="color: #007700">= array( </span><span style="color: #DD0000">'meaning' </span><span style="color: #007700">=&gt; </span><span style="color: #DD0000">'life'</span><span style="color: #007700">, </span><span style="color: #DD0000">'number' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">42 </span><span style="color: #007700">);<br /></span><span style="color: #0000BB">xdebug_debug_zval</span><span style="color: #007700">( </span><span style="color: #DD0000">'a' </span><span style="color: #007700">);<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
      </div>

      <div class="example-contents"><p>Resultado del ejemplo anterior es similar a:</p></div>
      <div class="example-contents screen">
<div class="cdata"><pre>
a: (refcount=1, is_ref=0)=array (
   &#039;meaning&#039; =&gt; (refcount=1, is_ref=0)=&#039;life&#039;,
   &#039;number&#039; =&gt; (refcount=1, is_ref=0)=42
)
</pre></div>
      </div>
      <div class="example-contents"><p>O gráficamente</p></div>
      <div class="mediaobject">
       
       <div class="imageobject">
        <img src="images/12f37b1c6963c1c5c18f30495416a197-simple-array.png" alt="Zvals de un array simple" width="593" height="143" />
       </div>
      </div>
     </div>
    </p>
    <p class="para">
     Los tres contenedores zval son: <var class="varname">a</var>, <var class="varname">meaning</var>, y
     <var class="varname">number</var>. Las mismas reglas se aplican para el incremento y la
     decrementación de los &quot;refcounts&quot;. A continuación, se añade otro elemento al array, y se asigna su valor con el contenido de un elemento ya existente del array:
    </p>
    <p class="para">
     <div class="example" id="example-6">
      <p><strong>Ejemplo #6 Añadir un elemento ya existente al array</strong></p>
      <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br />$a </span><span style="color: #007700">= array( </span><span style="color: #DD0000">'meaning' </span><span style="color: #007700">=&gt; </span><span style="color: #DD0000">'life'</span><span style="color: #007700">, </span><span style="color: #DD0000">'number' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">42 </span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$a</span><span style="color: #007700">[</span><span style="color: #DD0000">'life'</span><span style="color: #007700">] = </span><span style="color: #0000BB">$a</span><span style="color: #007700">[</span><span style="color: #DD0000">'meaning'</span><span style="color: #007700">];<br /></span><span style="color: #0000BB">xdebug_debug_zval</span><span style="color: #007700">( </span><span style="color: #DD0000">'a' </span><span style="color: #007700">);<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
      </div>

      <div class="example-contents"><p>Resultado del ejemplo anterior es similar a:</p></div>
      <div class="example-contents screen">
<div class="cdata"><pre>
a: (refcount=1, is_ref=0)=array (
   &#039;meaning&#039; =&gt; (refcount=2, is_ref=0)=&#039;life&#039;,
   &#039;number&#039; =&gt; (refcount=1, is_ref=0)=42,
   &#039;life&#039; =&gt; (refcount=2, is_ref=0)=&#039;life&#039;
)
</pre></div>
      </div>
      <div class="example-contents"><p>O gráficamente</p></div>
      <div class="mediaobject">
       
       <div class="imageobject">
        <img src="images/12f37b1c6963c1c5c18f30495416a197-simple-array2.png" alt="Zvals para un array simple con una referencia" width="593" height="143" />
       </div>
      </div>
     </div>
    </p>
    <p class="para">
     La salida Xdebug que vemos indica que el antiguo y el nuevo elemento del array
     apuntan ahora ambos a un contenedor zval cuyo &quot;refcount&quot; vale <code class="literal">2</code>.
     Aunque la salida XDebug muestra dos contenedores zval con el valor &#039;life&#039;, son los
     mismos. La función <span class="function"><strong>xdebug_debug_zval()</strong></span> no muestra esto, pero se podría ver
     mostrando también el puntero de memoria.
    </p>
    <p class="para">
     Eliminar un elemento del array es asimilable a la eliminación de un símbolo desde un
     espacio. Al hacerlo, el &quot;refcount&quot; del contenedor al que apunta el elemento del array se decrementa.
     Una vez más, si llega a cero, el contenedor zval se elimina de la memoria. El siguiente ejemplo lo demuestra:
    </p>
    <p class="para">
     <div class="example" id="example-7">
      <p><strong>Ejemplo #7 Eliminación de un elemento de array</strong></p>
      <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br />$a </span><span style="color: #007700">= array( </span><span style="color: #DD0000">'meaning' </span><span style="color: #007700">=&gt; </span><span style="color: #DD0000">'life'</span><span style="color: #007700">, </span><span style="color: #DD0000">'number' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">42 </span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$a</span><span style="color: #007700">[</span><span style="color: #DD0000">'life'</span><span style="color: #007700">] = </span><span style="color: #0000BB">$a</span><span style="color: #007700">[</span><span style="color: #DD0000">'meaning'</span><span style="color: #007700">];<br />unset( </span><span style="color: #0000BB">$a</span><span style="color: #007700">[</span><span style="color: #DD0000">'meaning'</span><span style="color: #007700">], </span><span style="color: #0000BB">$a</span><span style="color: #007700">[</span><span style="color: #DD0000">'number'</span><span style="color: #007700">] );<br /></span><span style="color: #0000BB">xdebug_debug_zval</span><span style="color: #007700">( </span><span style="color: #DD0000">'a' </span><span style="color: #007700">);<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
      </div>

      <div class="example-contents"><p>Resultado del ejemplo anterior es similar a:</p></div>
      <div class="example-contents screen">
<div class="cdata"><pre>
a: (refcount=1, is_ref=0)=array (
   &#039;life&#039; =&gt; (refcount=1, is_ref=0)=&#039;life&#039;
)
</pre></div>
      </div>
     </div>
    </p>
    <p class="para">
     Ahora, las cosas se vuelven interesantes si añadimos el array
     como elemento de sí mismo. Hacemos esto en el siguiente ejemplo, utilizando un
     operador de referencia para evitar que PHP cree una copia:
    </p>
    <p class="para">
     <div class="example" id="example-8">
      <p><strong>Ejemplo #8 Añadir el array como referencia a sí mismo como elemento</strong></p>
      <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br />$a </span><span style="color: #007700">= array( </span><span style="color: #DD0000">'one' </span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$a</span><span style="color: #007700">[] =&amp; </span><span style="color: #0000BB">$a</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">xdebug_debug_zval</span><span style="color: #007700">( </span><span style="color: #DD0000">'a' </span><span style="color: #007700">);<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
      </div>

      <div class="example-contents"><p>Resultado del ejemplo anterior es similar a:</p></div>
      <div class="example-contents screen">
<div class="cdata"><pre>
a: (refcount=2, is_ref=1)=array (
   0 =&gt; (refcount=1, is_ref=0)=&#039;one&#039;,
   1 =&gt; (refcount=2, is_ref=1)=...
)
</pre></div>
      </div>
      <div class="example-contents"><p>O gráficamente</p></div>
      <div class="mediaobject">
       
       <div class="imageobject">
        <img src="images/12f37b1c6963c1c5c18f30495416a197-loop-array.png" alt="Zvals en un array con referencia circular" width="533" height="144" />
       </div>
      </div>
     </div>
    </p>
    <p class="para">
     Se puede ver que la variable array (<var class="varname">a</var>) así como el segundo elemento
     (<var class="varname">1</var>) apuntan ahora a un contenedor cuyo &quot;refcount&quot; vale
     <code class="literal">2</code>. Los &quot;...&quot; en la visualización indican una recursión, que, en este caso,
     significa que el &quot;...&quot; apunta al array mismo.
    </p>
    <p class="para">
     Como antes, eliminar una variable elimina su símbolo, y el refcount del contenedor
     al que apuntaba se decrementa. Por lo tanto, si eliminamos la variable
     <var class="varname">$a</var> después de ejecutar el código anterior, el contador de referencias del
     contenedor al que apuntan <var class="varname">$a</var> y el elemento &quot;1&quot; se decrementará en uno,
     pasando de &quot;2&quot; a &quot;1&quot;. Esto se puede representar como:
    </p>
    <p class="para">
     <div class="example" id="example-9">
      <p><strong>Ejemplo #9 Eliminación de <var class="varname">$a</var></strong></p>
      <div class="example-contents screen">
<div class="cdata"><pre>
(refcount=1, is_ref=1)=array (
   0 =&gt; (refcount=1, is_ref=0)=&#039;one&#039;,
   1 =&gt; (refcount=1, is_ref=1)=...
)
</pre></div>
      </div>
      <div class="example-contents"><p>O gráficamente</p></div>
      <div class="mediaobject">
       
       <div class="imageobject">
        <img src="images/12f37b1c6963c1c5c18f30495416a197-leak-array.png" alt="Zvals después de la eliminación del array que contiene una referencia circular, fuga de memoria" width="463" height="144" />
       </div>
      </div>
     </div>
    </p>
   </div>

   <div class="sect2" id="features.gc.cleanup-problems">
    <h3 class="title">Problemas de limpieza</h3>
    <p class="para">
     Aunque ya no haya ningún símbolo en el espacio de variables actual que apunte
     a esta estructura, no puede ser limpiada, ya que el elemento &quot;1&quot; del array
     sigue apuntando a este mismo array. Como ya no hay ningún símbolo externo
     que apunte a esta estructura, el usuario no puede limpiarla manualmente;
     por lo tanto, hay una fuga de memoria. Afortunadamente, PHP destruirá esta estructura al final de
     la solicitud, pero antes de esta etapa, la memoria no se libera. Esta situación ocurre a menudo si se implementa un algoritmo de análisis u otras ideas donde se tiene un hijo que apunta a su padre. Lo mismo puede ocurrir, por supuesto, con los objetos, y es incluso más probable, ya que siempre se utilizan implícitamente por
     &quot;<a href="language.oop5.references.php" class="link">referencia</a>&quot;.
    </p>
    <p class="para">
     Esto puede no ser molesto si ocurre solo una o dos veces, pero si hay miles, o incluso millones,
     de estas fugas de memoria, entonces obviamente esto puede convertirse en un problema importante. Esto es particularmente problemático para los scripts
     que duran mucho tiempo, como los demonios para los cuales la solicitud nunca termina, o incluso en grandes suites de pruebas unitarias.
     Este último caso se encontró al lanzar las pruebas unitarias del componente Template de la
     biblioteca eZ Components. En algunos casos, la suite de pruebas requería más de 2Go de
     memoria, que el servidor de prueba no tenía realmente disponible.
    </p>
   </div>
  </div><?php manual_footer($setup); ?>