<?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 => 'ja',
  ),
  'this' => 
  array (
    0 => 'features.gc.refcounting-basics.php',
    1 => 'リファレンスカウントの原理',
    2 => 'リファレンスカウントの原理',
  ),
  'up' => 
  array (
    0 => 'features.gc.php',
    1 => 'ガベージコレクション',
  ),
  'prev' => 
  array (
    0 => 'features.gc.php',
    1 => 'ガベージコレクション',
  ),
  'next' => 
  array (
    0 => 'features.gc.collecting-cycles.php',
    1 => '循環の収集',
  ),
  'alternatives' => 
  array (
  ),
  'source' => 
  array (
    'lang' => 'ja',
    '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">リファレンスカウントの原理</h2>
   <p class="para">
    PHP 変数は「zval」と呼ばれるコンテナに保管されます。
    zval コンテナには、変数の型と値の他に、情報の追加ビットを2つ含みます。
    1つ目は「is_ref」と呼ばれ、変数が「参照集合」の一部かどうかを示すブール値
    です。
    このビットによって、通常の変数と参照を区別する方法を PHP エンジンが知ります。
    &amp;演算子によって作成されるように、PHP ではユーザーランドで参照を使えるので、
    zval コンテナもメモリー使用状況を最適化するための内部的なリファレンスカウント機構を
    持ちます。
    追加情報の2つ目は「refcount」と呼ばれ、この1つの zval コンテナをどれだけ多くの
    変数名（シンボルとも呼ばれます）が指すかを含みます。
    シンボルは全てシンボルテーブルに保管され、スコープごとにシンボルテーブルの
    1つがあります。
    関数やメソッドごとのスコープばかりではなく、メインスクリプト用のスコープ
    （すなわち、ブラウザによってリクエストされたスクリプト）があります。
   </p>
   <p class="para">
    新しい変数が定数値を使って作成されるとき、zval コンテナが作成されます。
    例えば、
    <div class="example" id="example-1">
     <p><strong>例1 新規 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">
    この例では、新しいシンボル名（<code class="literal">a</code>）が現在のスコープで作成され、
    新しい変数コンテナが <span class="type"><a href="language.types.string.php" class="type string">string</a></span> 型と値 <code class="literal">new string</code>
    で作成されます。
    「is_ref」ビットはデフォルトで <strong><code><a href="reserved.constants.php#constant.false">false</a></code></strong> にセットされます。なぜなら、ユーザーランド
    参照が作成されたことがないからです。
    この変数コンテナを利用するシンボルが1つだけあるので、「refcount」は
    <code class="literal">1</code> に設定されます。
    「refcount」を持つ参照 (&quot;is_ref&quot; ビットが <strong><code><a href="reserved.constants.php#constant.true">true</a></code></strong> の場合) が
    <code class="literal">1</code> の場合、
    参照されていないかのように
    (つまり、is_ref が常に <strong><code><a href="reserved.constants.php#constant.false">false</a></code></strong> であったかのように)
    扱われる点に注意してください。
    もし <a href="http://xdebug.org/" class="link external">&raquo;&nbsp;Xdebug</a> をインストール済みなら、
    <span class="function"><strong>xdebug_debug_zval()</strong></span>を呼ぶと、この情報を表示できます。
   </p>
   <p class="para">
    <div class="example" id="example-2">
     <p><strong>例2 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>上の例の出力は以下となります。</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">
    この変数を他の変数名に代入すると、refcount が増加します。
   </p>
   <p class="para">
    <div class="example" id="example-3">
     <p><strong>例3 zval の refcount を増加</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>上の例の出力は以下となります。</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">
    この時、refcount は <code class="literal">2</code> です。なぜなら、同じ変数コンテナが
    <var class="varname">a</var> と <var class="varname">b</var> にリンクされるからです。
    PHPは、必要ではない場合に実際の変数コンテナをコピーしないように十分スマートです。
    「refcount」がゼロに達すると、変数コンテナは破棄されます。
    変数コンテナにリンクされたあらゆるシンボルがスコープを抜ける
    (たとえば関数が終わる) 場合、またはシンボルへの代入が解除された
    (たとえば <span class="function"><a href="function.unset.php" class="function">unset()</a></span> が呼ばれた)
    場合に「refcount」が減少します。
    下記の例でこれを示します。
   </p>
   <p class="para">
    <div class="example" id="example-4">
     <p><strong>例4 zval refcount を減少</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>上の例の出力は以下となります。</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">
    次に、<code class="literal">unset($a);</code> を呼ぶと、（型と値を含む）変数コンテナが
    メモリから除去されます。
   </p>

   <div class="sect2" id="features.gc.compound-types">
    <h3 class="title">複合型</h3>

    <p class="para">
     <span class="type"><a href="language.types.array.php" class="type array">array</a></span> や <span class="type"><a href="language.types.object.php" class="type object">object</a></span> のような複合型では、事情が少し
     複雑になります。
     <span class="type">scalar</span> 値とは逆に、<span class="type"><a href="language.types.array.php" class="type array">array</a></span> と <span class="type"><a href="language.types.object.php" class="type object">object</a></span>
     では、それらのプロパティをそれら自身のシンボルテーブルに保管します。
     これは、以下の例が3つの zval コンテナを作成することを意味します。
    </p>
    <p class="para">
     <div class="example" id="example-5">
      <p><strong>例5 <span class="type"><a href="language.types.array.php" class="type array">array</a></span> 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">= 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>上の例の出力は、
たとえば以下のようになります。</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>つまり、図で示すと</p></div>
      <div class="mediaobject">
       
       <div class="imageobject">
        <img src="images/12f37b1c6963c1c5c18f30495416a197-simple-array.png" alt="単純配列に対する zval" width="593" height="143" />
       </div>
      </div>
     </div>
    </p>
    <p class="para">
     3つのzvalコンテナは <var class="varname">a</var>、<var class="varname">meaning</var> および
     <var class="varname">number</var> です。「refcount」の増減に同様のルールが適用されます。
     下記では、配列に他の要素を追加して、既存の要素の内容をその値に設定します。
    </p>
    <p class="para">
     <div class="example" id="example-6">
      <p><strong>例6 既存の要素を配列に追加</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>上の例の出力は、
たとえば以下のようになります。</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>つまり、図で示すと</p></div>
      <div class="mediaobject">
       
       <div class="imageobject">
        <img src="images/12f37b1c6963c1c5c18f30495416a197-simple-array2.png" alt="参照を使った単純配列に対する zval" width="593" height="143" />
       </div>
      </div>
     </div>
    </p>
    <p class="para">
     上記の Xdebug 出力では、新旧両方の配列要素が今や、refcount が <code class="literal">2</code>
     である zval コンテナを指すことがわかります。
     Xdebugの出力では、<code class="literal">&#039;life&#039;</code> という値の zval コンテナが2つ
     表示されますが、それらは同一です。
     <span class="function"><strong>xdebug_debug_zval()</strong></span> 関数はこれを表示しませんが、
     メモリ・ポインターを示すことによってもそれを確かめられます。
    </p>
    <p class="para">
     配列からの要素の除去は、スコープからシンボルを除去するようなものです。
     そうすることによって、配列要素が指すコンテナの「refcount」は、減少します。
     前と同じように、「refcount」がゼロに達すると、変数コンテナはメモリから
     除去されます。前と同じように、これを示す例です。
    </p>
    <p class="para">
     <div class="example" id="example-7">
      <p><strong>例7 配列から要素を除去</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>上の例の出力は、
たとえば以下のようになります。</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">
     次に、配列の要素として配列自体を追加すると、事情が面白くなります。
     次の例で行います、そこでは、参照演算子にこっそり入りもします。
     さもなければ PHP がコピーを作成するでしょう。
    </p>
    <p class="para">
     <div class="example" id="example-8">
      <p><strong>例8 それ自体の要素として配列自体を追加</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>上の例の出力は、
たとえば以下のようになります。</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>つまり、図で示すと</p></div>
      <div class="mediaobject">
       
       <div class="imageobject">
        <img src="images/12f37b1c6963c1c5c18f30495416a197-loop-array.png" alt="循環参照を使った配列に対する zval" width="533" height="144" />
       </div>
      </div>
     </div>
    </p>
    <p class="para">
     配列変数 (<var class="varname">a</var>) が２番目の要素 (<var class="varname">1</var>) と同様に
     「refcount」が <code class="literal">2</code> である変数コンテナを今や指していることがわかります。
     上記の表示の「...」は入り組んだ再帰があることを示します。
     もちろんこの場合には、「...」が元の配列を指すことを意味します。
    </p>
    <p class="para">
     ちょうど前のように、変数をアンセットするとシンボルが除去されます。
     そして指す変数コンテナのリファレンスカウントがアンセットにより減少します。
     従って、上記のコードを実行した後に変数 <var class="varname">$a</var> をアンセットすると、
     <var class="varname">$a</var> と要素「1」を指す変数コンテナのリファレンスカウントは、
     アンセットにより「2」から「1」に減少します。これは次のように表現されます。
    </p>
    <p class="para">
     <div class="example" id="example-9">
      <p><strong>例9 <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>つまり、図で示すと</p></div>
      <div class="mediaobject">
       
       <div class="imageobject">
        <img src="images/12f37b1c6963c1c5c18f30495416a197-leak-array.png" alt="メモリ・リークを実際に示す循環参照を使った配列を除去した後の zval" width="463" height="144" />
       </div>
      </div>
     </div>
    </p>
   </div>

   <div class="sect2" id="features.gc.cleanup-problems">
    <h3 class="title">片づけの問題</h3>
    <p class="para">
     この構造体を指すシンボルがいかなるスコープにももはや存在しないにもかかわらず、
     配列要素「1」がこの同じ配列をまだ指すので、片づけられません。
     それを指している外部シンボルがないので、ユーザーがこの構造体を片付ける方法が
     ありません。このようにしてメモリーリークとなります。
     幸いにも、PHP はリクエスト終了後、このデータ構造を片付けます、しかし、それ以前に
     これはメモリ内の貴重な空間を占めています。
     この状態は、「親」要素に再帰する「子」を持つ構文解析アルゴリズムなどの実装中に
     しばしば発生します。
     もちろんオブジェクトでも同じ状態が起こり得ます。オブジェクトは常に暗黙のうちに
     <a href="language.oop5.references.php" class="link">リファレンス</a> によって使われるので、実はその状態がより起こりそうです。
    </p>
    <p class="para">
     これが 1、2 回起こるだけであるならば、これは問題でないかもしれません。しかし、
     これらのメモリ損失の数千または数百万さえあるならば、これは明らかに問題になり始めます。
     これは、例えばリクエストが基本的に決して終わらないデーモンのような、長くかかる
     実行中のスクリプトや、単体テストの大規模な集合で特に問題があります。
     後者は、eZ コンポーネント・ライブラリのテンプレート・コンポーネントに対して
     単体テストを実行中に問題を引き起こしました。
     事例によっては、2GB 以上のメモリが必要でしたが、テストサーバーは全く
     持っていませんでした。
    </p>
   </div>
  </div><?php manual_footer($setup); ?>