<?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 => 'de',
  ),
  'this' => 
  array (
    0 => 'features.gc.performance-considerations.php',
    1 => 'Leistungsrelevante &Uuml;berlegungen',
    2 => 'Leistungsrelevante &Uuml;berlegungen',
  ),
  'up' => 
  array (
    0 => 'features.gc.php',
    1 => 'Garbage Collection (Speicherbereinigung)',
  ),
  'prev' => 
  array (
    0 => 'features.gc.collecting-cycles.php',
    1 => 'Sammeln zyklischer Referenzen',
  ),
  'next' => 
  array (
    0 => 'features.dtrace.php',
    1 => 'DTrace Dynamic Tracing (Anwendungsanalyse in Echtzeit)',
  ),
  'alternatives' => 
  array (
  ),
  'source' => 
  array (
    'lang' => 'de',
    '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">Leistungsrelevante Überlegungen</h2>
   <p class="para">
    Wie bereits im vorangegangenen Abschnitt erwähnt, wirkt sich das einfache
    Sammeln der möglichen Wurzeln nur geringfügig auf die Leistung aus. Dies
    gilt jedoch nur im Vergleich zwischen PHP 5.2 und PHP 5.3. Obwohl die
    Aufzeichnung möglicher Wurzeln langsamer ist als wenn sie wie in PHP 5.2
    überhaupt nicht aufgezeichnet werden, haben andere Änderungen an der
    PHP-Laufzeit in PHP 5.3 verhindert, dass dieser spezielle Leistungsverlust
    überhaupt sichtbar wird.
   </p>
   <p class="para">
    Es gibt zwei Hauptbereiche, in denen die Leistung betroffen ist. Der erste
    Bereich ist die verringerte Speichernutzung und der zweite Bereich ist die
    Laufzeitverzögerung, wenn der Mechanismus der Garbage Collection seine
    Speicherbereinigungen durchführt. Um diese beiden Punkte geht es im
    Folgenden.
   </p>

   <div class="sect2" id="features.gc.performance-considerations.reduced-mem">
    <h3 class="title">Verringerte Speichernutzung</h3>
    <p class="para">
     In erster Linie soll durch die Implementierung des Mechanismus der
     Garbage Collection der Speicherverbrauch reduziert werden, indem zirkulär
     referenzierte Variablen gelöscht werden, sobald die Voraussetzungen dafür
     erfüllt sind. In der PHP-Implementierung geschieht dies, sobald der
     Wurzelpuffer voll ist oder wenn die Funktion
     <span class="function"><a href="function.gc-collect-cycles.php" class="function">gc_collect_cycles()</a></span> aufgerufen wird. Im folgenden
     Diagramm wird der Speicherverbrauch eines Skripts sowohl in PHP 5.2 als
     auch in PHP 5.3 dargestellt, wobei der Basisspeicher, den PHP selbst beim
     Starten verwendet, nicht berücksichtigt wird.
    </p>
    <p class="para">
     <div class="example" id="example-1">
      <p><strong>Beispiel #1 Beispiel für die Speichernutzung</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="Vergleich der Speichernutzung von PHP 5.2 und PHP 5.3" width="850" height="480" />
       </div>
      </div>
     </div>
    </p>
    <p class="para">
     In diesem sehr theoretischen Beispiel wird ein Objekt erstellt, in dem
     eine Eigenschaft so gesetzt wird, dass sie auf das Objekt selbst
     zurückverweist. Wenn die Variable <var class="varname">$a</var> im Skript in der
     nächsten Iteration der Schleife neu zugewiesen wird, kommt es
     normalerweise zu einem Speicherleck. In diesem Fall sind zwei
     zval-Container betroffen (das Objekt zval und die Eigenschaft zval), aber
     es wird nur eine mögliche Wurzel gefunden: die Variable, die nicht
     gesetzt wurde. Wenn der Wurzelpuffer nach 10.000 Iterationen (mit
     insgesamt 10.000 möglichen Wurzeln) voll ist, setzt der Mechanismus der
     Garbage Collection ein und gibt den mit diesen möglichen Wurzeln
     verbundenen Speicher frei. Dies ist sehr deutlich in der gezackten Grafik
     der Speichernutzung für PHP 5.3 zu sehen. Nach jeweils 10.000
     Iterationen schaltet sich der Mechanismus ein und gibt den Speicher frei,
     der mit den zirkulär referenzierten Variablen verbunden ist. Der
     Mechanismus selbst muss in diesem Beispiel nicht viel Arbeit leisten, da
     die Struktur, die das Leck aufweist, extrem einfach ist. Aus dem Diagramm
     ist ersichtlich, dass der maximale Speicherverbrauch in PHP 5.3 etwa 9 MB
     beträgt, während der Speicherverbrauch in PHP 5.2 stetig ansteigt.
    </p>
   </div>

   <div class="sect2" id="features.gc.performance-considerations.slowdowns">
    <h3 class="title">Verzögerungen in der Laufzeit</h3>
    <p class="para">
     Der zweite Bereich, in dem der Mechanismus der Garbage Collection die
     Leistung beeinflusst, ist die Zeit, die benötigt wird, wenn die Garbage
     Collection einsetzt, um den &quot;ausgelaufenen&quot; Speicher freizugeben. Um zu
     sehen, wieviel das ist, wird das vorherige Skript leicht abgeändert, um
     eine größere Anzahl von Iterationen zu ermöglichen und die Zahlen für die
     zwischenzeitliche Speichernutzung zu entfernen. Das zweite Skript ist
     hier:
    </p>
    <p class="para">
     <div class="example" id="example-2">
      <p><strong>Beispiel #2 Einfluss der GC auf die Leistung</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">
     Dieses Skript wird zweimal ausgeführt, einmal ist die Einstellung
     <a href="info.configuration.php#ini.zend.enable-gc" class="link">zend.enable_gc</a> aktiviert und
     einmal ist sie deaktiviert:
    </p>
    <p class="para">
     <div class="example" id="example-3">
      <p><strong>Beispiel #3 Ausführen des obigen Skripts</strong></p>
      <div class="example-contents">
<div class="shellcode"><pre class="shellcode">time php -dzend.enable_gc=0 -dmemory_limit=-1 -n example2.php
# und
time php -dzend.enable_gc=1 -dmemory_limit=-1 -n example2.php</pre>
</div>
      </div>

     </div>
    </p>
    <p class="para">
     Auf dem verwendeten Rechner scheint der erste Befehl konstant etwa 10,7
     Sekunden zu dauern, während der zweite Befehl etwa 11,4 Sekunden
     benötigt. Das ist eine Verlangsamung um etwa 7%. Der vom Skript maximal
     benötigte Speicherplatz wird jedoch um 98% von 931 MB auf 10 MB
     reduziert. Dieser Benchmark ist nicht sehr wissenschaftlich oder gar
     repräsentativ für reale Anwendungen, aber er zeigt die Vorteile, die
     dieser Mechanismus der Garbage Collection bei der Speichernutzung bietet.
     Das Gute daran ist, dass die Verlangsamung bei diesem speziellen Skript
     immer dieselben 7% beträgt, während die Fähigkeit, Speicher zu sparen,
     immer mehr Speicher einspart, je mehr zirkuläre Referenzen während der
     Ausführung des Skripts gefunden werden.
    </p>
   </div>

   <div class="sect2" id="features.gc.performance-considerations.internal-stats">
    <h3 class="title">PHPs interne GC-Statistik</h3>
    <p class="para">
     Es ist möglich, PHP etwas mehr Informationen darüber zu entlocken, wie
     der Mechanismus der Garbage Collection abläuft. Dazu muss PHP jedoch neu
     kompiliert werden, um den Code für den Benchmark und die Datenerfassung
     zu aktivieren. Bevor <code class="literal">./configure</code> mit den gewünschten
     Optionen ausgeführt wird, muss die Umgebungsvariable
     <code class="literal">CFLAGS</code> auf <code class="literal">-DGC_BENCH=1</code> gesetzt
     werden. Die folgende Befehlsfolge sollte dafür genügen:
    </p>
    <p class="para">
     <div class="example" id="example-4">
      <p><strong>Beispiel #4 PHP neu kompilieren, um das GC-Benchmarking zu aktivieren</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">
     Wenn der obige Beispielcode mit der neu erstellten PHP-Binärdatei erneut
     ausgeführt wird, wird Folgendes angezeigt, nachdem PHP die Ausführung
     beendet hat:
    </p>
    <p class="para">
     <div class="example" id="example-5">
      <p><strong>Beispiel #5 GC-Statistik</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">
     Die aufschlussreichste Statistik wird im ersten Block angezeigt. Hier ist
     zu sehen, dass der Mechanismus der Garbage Collection 110 mal ausgeführt
     wurde und bei diesen 110 Durchläufen insgesamt mehr als 2 Millionen
     Speicherzuweisungen freigegeben wurden. Nachdem der Mechanismus der
     Garbage Collection mindestens einmal gelaufen ist, beträgt der &quot;Root
     buffer peak&quot; immer 10000.
    </p>
   </div>

   <div class="sect2" id="features.gc.performance-considerations.conclusion">
    <h3 class="title">Zusammenfassung</h3>
    <p class="para">
     Im Allgemeinen führt der Garbage Collector in PHP nur dann zu einer
     Verlangsamung, wenn der Algorithmus für die Zyklussammlung tatsächlich
     ausgeführt wird, während es bei normalen (kleineren) Skripten zu
     keinerlei Leistungseinbußen kommen sollte.
    </p>
    <p class="para">
     In den Fällen, in denen der Mechanismus für die Zyklussammlung bei
     normalen Skripten ausgeführt wird, ermöglicht die damit verbundene
     Reduzierung des Speicherbedarfs die gleichzeitige Ausführung von mehr
     Skripten auf dem Server, da insgesamt weniger Speicher benötigt wird.
    </p>
    <p class="para">
     Die Vorteile sind am deutlichsten bei länger laufenden Skripten, z. B.
     bei langen Testsuiten oder Daemon-Skripten. Auch für
     <a href="http://gtk.php.net/" class="link external">&raquo;&nbsp;PHP-GTK</a>-Anwendungen, die in der
     Regel länger laufen als Skripte für das Web, sollte der neue Mechanismus
     einen großen Unterschied in Bezug auf Speicherlecks machen, die sich mit
     der Zeit einschleichen.
    </p>
   </div>
  </div><?php manual_footer($setup); ?>