<?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 => 'pt_BR',
  ),
  'this' => 
  array (
    0 => 'features.gc.performance-considerations.php',
    1 => 'Considera&ccedil;&otilde;es de Desempenho',
    2 => 'Considera&ccedil;&otilde;es de Desempenho',
  ),
  'up' => 
  array (
    0 => 'features.gc.php',
    1 => 'Coletor de Lixo',
  ),
  'prev' => 
  array (
    0 => 'features.gc.collecting-cycles.php',
    1 => 'Ciclos de Coleta',
  ),
  'next' => 
  array (
    0 => 'features.dtrace.php',
    1 => 'Instrumenta&ccedil;&atilde;o din&acirc;mica DTrace',
  ),
  'alternatives' => 
  array (
  ),
  'source' => 
  array (
    'lang' => 'pt_BR',
    '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">Considerações de Desempenho</h2>
   <p class="para">
    Já foi mencionado na seção anterior que simplesmente coletar as
    raízes possíveis tem um impacto muito pequeno em desempenho, mas isso quando
    compara-se o PHP 5.2 com o PHP 5.3. Embora o registro de raízes possíveis
    comparado ao não registro, como no PHP 5.2, seja mais lento, outras
    mudanças em tempo de execução no PHP 5.3 evitam que esta perda particular
    de desempenho apareça.
   </p>
   <p class="para">
    Existem duas grandes áreas onde o desempenho é afetado. A primeira
    é o uso reduzido de memória, e a segunda é o atraso em tempo de execução
    quando o mecanismo de coleta de lixo faz suas limpezas de memória. Estes
    dois problemas serão mostrados a seguir.
   </p>

   <div class="sect2" id="features.gc.performance-considerations.reduced-mem">
    <h3 class="title">Uso Reduzido de Memória</h3>
    <p class="para">
     Primeiramente, o grande motivo pelo qual o mecanismo de coleta de lixo
     existe é para reduzir o uso de memória através de limpeza de variáveis
     em referência circular assim que os pré-requisitos são preenchidos. Na
     implementação do PHP, isso acontece assim que o buffer de raízes fica cheio, ou
     quando a função <span class="function"><a href="function.gc-collect-cycles.php" class="function">gc_collect_cycles()</a></span> é chamada. No
     gráfico abaixo, é mostrado o uso de memória do script a seguir,
     tanto no PHP 5.2 quanto no PHP 5.3, excluindo a memória básica que o próprio
     PHP usa quando se inicia.
    </p>
    <p class="para">
     <div class="example" id="example-1">
      <p><strong>Exemplo #1 Exemplo de uso de memória</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="Comparação de uso de memória entre o PHP 5.2 e o PHP 5.3" width="850" height="480" />
       </div>
      </div>
     </div>
    </p>
    <p class="para">
     Neste exemplo bem acadêmico, está sendo criado um objeto no qual
     uma propriedade é definida para apontar para o próprio objeto. Quando a variável <var class="varname">$a</var>
     no script é re-atribuída na iteração seguinte do loop, um vazamento de
     memória normalmente iria acontecer. Neste caso, dois contêineres são vazados
     (o zval objeto e o zval propriedade), mas apenas uma raiz possível é
     encontrada: a variável que perdeu a atribuição. Quando o buffer de raízes está cheio
     depois de 10.000 iterações (com um total de 10.000 raízes possíveis), o mecanismo
     de coleta de lixo entra e libera a memória associada com essas
     raízes possíveis. Isto pode ser visto claramente com o gráfico irregular
     de uso de memória para o PHP 5.3. Depois de 10.000 iterações, o mecanismo entre
     e libera a memória associada com as variáveis com referência circular..
     O mecanismo em si não tem muito trabalho neste exemplo,
     porque a estrutura que é vazada é extremamente simples. Pelo
     diagrama, pode-se verificar que o uso de memória no PHP 5.3 é de aproximadamente
     9Mb, enquanto que no PHP 5.2 o uso de memória continua crescendo.
    </p>
   </div>

   <div class="sect2" id="features.gc.performance-considerations.slowdowns">
    <h3 class="title">Atraso em Tempo de Execução</h3>
    <p class="para">
     A segunda área onde o mecanismo de coleta de lixo influencia o
     desempenho é o tempo gasto quando o mecanismo entra
     para liberar a memória &quot;vazada&quot;. Para verificar quanto é este tempo,
     o script anterior foi minimamente modificado para permitir um número maior de
     iterações e a remoção dos números de uso de memória intermediária. O
     segundo script está apresentado a seguir:
    </p>
    <p class="para">
     <div class="example" id="example-2">
      <p><strong>Exemplo #2 Influência do Coletor de Lixo no desempenho</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">
     O script será executado duas vezes, uma com a configuração
     <a href="info.configuration.php#ini.zend.enable-gc" class="link">zend.enable_gc</a> habilitada,
     e outra desabilitada:
    </p>
    <p class="para">
     <div class="example" id="example-3">
      <p><strong>Exemplo #3 Executando o script acima</strong></p>
      <div class="example-contents">
<div class="shellcode"><pre class="shellcode">time php -dzend.enable_gc=0 -dmemory_limit=-1 -n example2.php
# e
time php -dzend.enable_gc=1 -dmemory_limit=-1 -n example2.php</pre>
</div>
      </div>

     </div>
    </p>
    <p class="para">
     Em uma máquina específica, o primeiro comando parece levar 10.7 segundos,
     enquanto que o segundo leva 11.4 segundos. Isto é um atraso de
     aproximadamente 7%. Entretanto, a quantidade máxima de memória usada pelo
     script é reduzida em 98%, de 931Mb para 10Mb. Esta referência não é muito
     científica, ou mesmo representativa para aplicações do mundo real, mas
     demonstra os benefícios de uso de memória que este mecanismo de coleta
     de lixo fornece. A boa notícia é que este atraso é sempre de
     7% para este script particular, enquanto que as capacidades de
     redução de memória economizam mais e mais memória quando referências
     circulares adicionais são encontradas durante a execução do script.
    </p>
   </div>

   <div class="sect2" id="features.gc.performance-considerations.internal-stats">
    <h3 class="title">Estatísticas de GC Internas do PHP</h3>
    <p class="para">
     É possível obter um pouco mais de informação sobre como o
     o mecanismo de coleta de lixo é executado no PHP. Mas para fazer isto,
     deve-se recompilar o PHP para habilitar o benchmark e o
     código de coleta de dados. Deve-se definir a variável de ambiente
     <code class="literal">CFLAGS</code> para <code class="literal">-DGC_BENCH=1</code> antes de executar
     <code class="literal">./configure</code> com as opções desejadas. A sequência a
     seguir deve fazer este truque:
    </p>
    <p class="para">
     <div class="example" id="example-4">
      <p><strong>Exemplo #4 Recompilando o PHP para habilitar o benchmarking de 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">
     Quando o exemplo acima for executado novamente com o novo
     binário do PHP, o resultado abaixo será visualizado assim que o
     PHP terminar a execução:
    </p>
    <p class="para">
     <div class="example" id="example-5">
      <p><strong>Exemplo #5 Estatí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">
     As estatísticas mais informativas são mostradas no primeiro bloco. Pode-se
     ver aqui que o mecanismo de coleta de lixo foi executado 110 vezes, e no
     total, mais de 2 milhões de alocações de memória foram liberadas durante estas
     110 execuções. Assim que o mecanismo tenha sido executado pelo menos
     uma vez, o &quot;Root buffer peak&quot; (pico do buffer de raízes) será sempre 10.000.
    </p>
   </div>

   <div class="sect2" id="features.gc.performance-considerations.conclusion">
    <h3 class="title">Conclusão</h3>
    <p class="para">
     Em geral, o coletor de lixo no PHP irá causar um atraso apenas quando
     o algoritmo de coleta realmente for executado, enquanto que em scripts normais
     (menores), não deve haver nenhum prejuízo no desempenho.
    </p>
    <p class="para">
     Entretanto, em casos onde o mecanismo de coleta é executado em
     scripts normais, a redução de memória que ele vai proporcionar irá permitir
     que mais desses scripts possam ser executados ao mesmo tempo no servidor, já que
     a quantidade de memória usada no total não será muito grande.
    </p>
    <p class="para">
     Os benefícios são mais aparentes para scripts de longa execução, como os
     scripts de conjunto de testes ou daemons. Adicionalmente, para aplicações <a href="http://gtk.php.net/" class="link external">&raquo;&nbsp;PHP-GTK</a>
     que geralmente tendem a rodar por mais tempo que scripts para a Web, o novo
     mecanismo deve fazer uma diferença considerável em relação a vazamentos
     de memória que insistem em acontecer.
    </p>
   </div>
  </div><?php manual_footer($setup); ?>