<?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.performance-considerations.php',
    1 => 'Consideraciones sobre el rendimiento',
    2 => 'Consideraciones sobre el rendimiento',
  ),
  'up' => 
  array (
    0 => 'features.gc.php',
    1 => 'Recolecci&oacute;n de basura (Garbage Collection)',
  ),
  'prev' => 
  array (
    0 => 'features.gc.collecting-cycles.php',
    1 => 'Limpieza de Ciclos',
  ),
  'next' => 
  array (
    0 => 'features.dtrace.php',
    1 => 'Rastreo din&aacute;mico de DTrace',
  ),
  '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.performance-considerations" class="sect1">
   <h2 class="title">Consideraciones sobre el rendimiento</h2>
   <p class="para">
    Ya se ha visto en las secciones anteriores que la recolección de raíces probables
    tenía un impacto muy ligero en el rendimiento, pero esto es en comparación con PHP 5.2 a
    PHP 5.3. Aunque el registro de raíces probables es más lento que no registrarlas en absoluto, como en PHP 5.2, otras mejoras aportadas por PHP 5.3
    hacen que esta operación no se sienta a nivel de rendimiento.
   </p>
   <p class="para">
    Hay principalmente dos niveles para los cuales se afecta el rendimiento.
    El primero es la huella de memoria reducida, y el segundo es el retraso en la ejecución,
    cuando el mecanismo de limpieza realiza su operación de liberación de memoria.
    Se estudiarán estos dos ejes.
   </p>

   <div class="sect2" id="features.gc.performance-considerations.reduced-mem">
    <h3 class="title">Huella de memoria reducida</h3>
    <p class="para">
     En primer lugar, la razón principal de la implementación del mecanismo de recolección de basura
     es la reducción de la memoria consumida, limpiando las referencias circulares cuando
     se cumplen las condiciones requeridas.
     Con PHP, esto ocurre tan pronto como el búfer de raíces está lleno, o cuando se llama a la
     función <span class="function"><a href="function.gc-collect-cycles.php" class="function">gc_collect_cycles()</a></span>. En el gráfico a continuación, se muestra el uso de memoria del siguiente script, con PHP 5.2 y con PHP 5.3, excluyendo
     la memoria obligatoria que PHP consume por sí mismo al inicio.
    </p>
    <p class="para">
     <div class="example" id="example-1">
      <p><strong>Ejemplo #1 Ejemplo de uso de memoria</strong></p>
      <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /></span><span style="color: #007700">class </span><span style="color: #0000BB">Foo<br /></span><span style="color: #007700">{<br />    public </span><span style="color: #0000BB">$var </span><span style="color: #007700">= </span><span style="color: #DD0000">'3.14159265359'</span><span style="color: #007700">;<br />    public </span><span style="color: #0000BB">$self</span><span style="color: #007700">;<br />}<br /><br /></span><span style="color: #0000BB">$baseMemory </span><span style="color: #007700">= </span><span style="color: #0000BB">memory_get_usage</span><span style="color: #007700">();<br /><br />for ( </span><span style="color: #0000BB">$i </span><span style="color: #007700">= </span><span style="color: #0000BB">0</span><span style="color: #007700">; </span><span style="color: #0000BB">$i </span><span style="color: #007700">&lt;= </span><span style="color: #0000BB">100000</span><span style="color: #007700">; </span><span style="color: #0000BB">$i</span><span style="color: #007700">++ )<br />{<br />    </span><span style="color: #0000BB">$a </span><span style="color: #007700">= new </span><span style="color: #0000BB">Foo</span><span style="color: #007700">;<br />    </span><span style="color: #0000BB">$a</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">self </span><span style="color: #007700">= </span><span style="color: #0000BB">$a</span><span style="color: #007700">;<br />    if ( </span><span style="color: #0000BB">$i </span><span style="color: #007700">% </span><span style="color: #0000BB">500 </span><span style="color: #007700">=== </span><span style="color: #0000BB">0 </span><span style="color: #007700">)<br />    {<br />        echo </span><span style="color: #0000BB">sprintf</span><span style="color: #007700">( </span><span style="color: #DD0000">'%8d: '</span><span style="color: #007700">, </span><span style="color: #0000BB">$i </span><span style="color: #007700">), </span><span style="color: #0000BB">memory_get_usage</span><span style="color: #007700">() - </span><span style="color: #0000BB">$baseMemory</span><span style="color: #007700">, </span><span style="color: #DD0000">"\n"</span><span style="color: #007700">;<br />    }<br />}<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
      </div>

      <div class="mediaobject">
       
       <div class="imageobject">
        <img src="images/12f37b1c6963c1c5c18f30495416a197-gc-benchmark.png" alt="Comparación del consumo de memoria entre PHP 5.2 y PHP 5.3" width="850" height="480" />
       </div>
      </div>
     </div>
    </p>
    <p class="para">
     En este ejemplo algo académico, se crea un objeto que tiene un atributo que se referencia
     a sí mismo. Cuando la variable <var class="varname">$a</var> en el script se reasigna a
     la siguiente iteración, aparecerá una fuga de memoria. En este caso, los dos contenedores zval
     se fugan (el zval del objeto y el del atributo), pero solo se encuentra una raíz probable:
     la variable que ha sido eliminada. Cuando el búfer de raíces está lleno después de
     10.000 iteraciones (con un total de 10.000 raíces probables), el mecanismo de recolección de basura entra en juego y libera la memoria asociada a estas raíces probables. Esto se ve
     muy claramente en los gráficos de uso de memoria de PHP 5.3. Después de cada 10.000
     iteraciones, el mecanismo se desencadena y libera la memoria asociada a las variables circularmente
     referenciadas. El mecanismo en cuestión no tiene mucho trabajo en este ejemplo, porque la estructura que se fugó es extremadamente simple.
     El diagrma muestra que el uso máximo de memoria de PHP 5.3 es de aproximadamente
     9Mo, mientras que sigue aumentando con PHP 5.2.
    </p>
   </div>

   <div class="sect2" id="features.gc.performance-considerations.slowdowns">
    <h3 class="title">Ralentizaciones durante la ejecución</h3>
    <p class="para">
     El segundo punto donde el mecanismo de recolección de basura (GC) afecta el rendimiento
     es cuando se ejecuta para liberar la memoria &quot;desperdiciada&quot;. Para cuantificar este
     impacto, se modifica ligeramente el script anterior para tener un número de iteraciones
     más alto y eliminar la recolección del uso de memoria intermedia.
     El segundo script se reproduce a continuación:
    </p>
    <p class="para">
     <div class="example" id="example-2">
      <p><strong>Ejemplo #2 Impacto de GC en el rendimiento</strong></p>
      <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /></span><span style="color: #007700">class </span><span style="color: #0000BB">Foo<br /></span><span style="color: #007700">{<br />    public </span><span style="color: #0000BB">$var </span><span style="color: #007700">= </span><span style="color: #DD0000">'3.14159265359'</span><span style="color: #007700">;<br />    public </span><span style="color: #0000BB">$self</span><span style="color: #007700">;<br />}<br /><br />for ( </span><span style="color: #0000BB">$i </span><span style="color: #007700">= </span><span style="color: #0000BB">0</span><span style="color: #007700">; </span><span style="color: #0000BB">$i </span><span style="color: #007700">&lt;= </span><span style="color: #0000BB">1000000</span><span style="color: #007700">; </span><span style="color: #0000BB">$i</span><span style="color: #007700">++ )<br />{<br />    </span><span style="color: #0000BB">$a </span><span style="color: #007700">= new </span><span style="color: #0000BB">Foo</span><span style="color: #007700">;<br />    </span><span style="color: #0000BB">$a</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">self </span><span style="color: #007700">= </span><span style="color: #0000BB">$a</span><span style="color: #007700">;<br />}<br /><br />echo </span><span style="color: #0000BB">memory_get_peak_usage</span><span style="color: #007700">(), </span><span style="color: #DD0000">"\n"</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
      </div>

     </div>
    </p>
    <p class="para">
     Se lanzará este script 2 veces, una vez con
     <a href="info.configuration.php#ini.zend.enable-gc" class="link">zend.enable_gc</a> en on, y una vez en off:
    </p>
    <p class="para">
     <div class="example" id="example-3">
      <p><strong>Ejemplo #3 Ejecución del script anterior</strong></p>
      <div class="example-contents">
<div class="shellcode"><pre class="shellcode">time php -dzend.enable_gc=0 -dmemory_limit=-1 -n example2.php
# y
time php -dzend.enable_gc=1 -dmemory_limit=-1 -n example2.php</pre>
</div>
      </div>

     </div>
    </p>
    <p class="para">
     En mi máquina, el primer comando parece durar siempre 10,7 segundos,
     mientras que el segundo comando tarda aproximadamente 11,4 segundos. Esto corresponde a un retraso
     de aproximadamente el 7%. Sin embargo, la cantidad total de memoria utilizada por el script se reduce
     en un 98%, pasando de 931Mo a 10Mo. Este benchmark no es muy científico ni representativo de aplicaciones reales, pero demuestra concretamente en qué medida el mecanismo
     de recolección de basura puede ser útil en términos de consumo de memoria. El punto positivo es que el retraso es siempre del 7%, en el caso particular de este script, mientras que
     la memoria preservada será cada vez más importante a medida que
     aparezcan referencias circulares durante la ejecución.
    </p>
   </div>

   <div class="sect2" id="features.gc.performance-considerations.internal-stats">
    <h3 class="title">Estadísticas internas del GC de PHP</h3>
    <p class="para">
     Es posible obtener algunas informaciones adicionales concernientes al mecanismo de recolección de basura
     interno de PHP. Pero para ello, se debe recompilar PHP con el soporte
     de benchmarking y recolección de datos. Se debe establecer la variable
     de entorno <code class="literal">CFLAGS</code> con <code class="literal">-DGC_BENCH=1</code> antes
     de lanzar <code class="literal">./configure</code> con las opciones que interesan.
     El siguiente ejemplo lo demuestra:
    </p>
    <p class="para">
     <div class="example" id="example-4">
      <p><strong>Ejemplo #4 Recompilar PHP para activar el soporte de benchmark del GC</strong></p>
      <div class="example-contents">
<div class="shellcode"><pre class="shellcode">export CFLAGS=-DGC_BENCH=1
./config.nice
make clean
make</pre>
</div>
      </div>

     </div>
    </p>
    <p class="para">
     Cuando se re-ejecuta el código del script anterior con el binario PHP recién reconstruido, se debería ver el siguiente resultado después de la ejecución:
    </p>
    <p class="para">
     <div class="example" id="example-5">
      <p><strong>Ejemplo #5 Estadísticas GC</strong></p>
      <div class="example-contents">
<div class="shellcode"><pre class="shellcode">GC Statistics
-------------
Runs:               110
Collected:          2072204
Root buffer length: 0
Root buffer peak:   10000

      Possible            Remove from  Marked
        Root    Buffered     buffer     grey
      --------  --------  -----------  ------
ZVAL   7175487   1491291    1241690   3611871
ZOBJ  28506264   1527980     677581   1025731</pre>
</div>
      </div>

     </div>
    </p>
    <p class="para">
     Las estadísticas más interesantes se muestran en el primer bloque. Se ve aquí
     que el mecanismo de recolección de basura se ha desencadenado 110 veces, y que en total son
     más de 2 millones de asignaciones de memoria las que se han liberado durante estos 110 pasos.
     Tan pronto como el mecanismo haya intervenido al menos una vez, el pico del búfer de raíces es siempre
     de 10000.
    </p>
   </div>

   <div class="sect2" id="features.gc.performance-considerations.conclusion">
    <h3 class="title">Conclusión</h3>
    <p class="para">
     En general, la recolección de basura de PHP solo causará un retraso
     cuando el algoritmo de recolección de ciclos se ejecute, lo que significa que en los scripts
     normales (más cortos), no debería haber ningún impacto en el rendimiento.
    </p>
    <p class="para">
     Sin embargo, cuando el mecanismo de recolección de ciclos se desencadene en scripts
     normales, la reducción de la huella de memoria permitirá la ejecución paralela de un número mayor de estos scripts, ya que se utilizará menos memoria en total.
    </p>
    <p class="para">
     Las ventajas se sienten más claramente en el caso de scripts demonio o que deben ejecutarse durante mucho tiempo. Así, para las aplicaciones <a href="http://gtk.php.net/" class="link external">&raquo;&nbsp;PHP-GTK</a> que a menudo
     duran más que los scripts web, el nuevo mecanismo debería reducir
     significativamente las fugas de memoria a largo plazo.
    </p>
   </div>
  </div><?php manual_footer($setup); ?>