前書き: PHP はマネージ言語です。PHP プログラミングでは、プログラマはメモリ リソースの割り当てと解放を手動で処理する必要がありません (C で PHP または Zend 拡張機能を作成する場合を除く)。これは、PHP 自体がガベージ コレクション メカニズムを実装していることを意味します。 (ガベージコレクション)。 PHP 公式 Web サイト (php.net) にアクセスすると、PHP5 の 2 つのブランチ バージョン、PHP5.2 と PHP5.3 が別々に更新されていることがわかります。これは、多くのプロジェクトが依然として PHP 5.2 バージョンを使用しているためです。 5.3 バージョンと 5.2 には完全な互換性がありません。 PHP5.3 では PHP5.2 をベースに多くの改良が加えられており、その中でもガベージコレクションのアルゴリズムは比較的大きな変更となっています。この記事では、PHP5.2 と PHP5.3 のガベージ コレクション メカニズムについてそれぞれ説明し、この進化と改善が PHP を作成するプログラマに与える影響と注意すべき問題について説明します。
PHP変数と関連メモリオブジェクトの内部表現
最終的に、ガベージ コレクションは変数とそれに関連付けられたメモリ オブジェクトの操作です。そのため、PHP のガベージ コレクション メカニズムについて説明する前に、PHP における変数とそのメモリ オブジェクトの内部表現 (C ソース コードでの表現) を簡単に紹介しましょう。 。
公式 PHP ドキュメントでは、PHP の変数をスカラー型と複合型の 2 つのカテゴリに分類しています。スカラー型にはブール型、整数型、浮動小数点型、文字列が含まれ、複合型には配列、オブジェクト、リソースが含まれます。また、どの型にも分割されず、別のカテゴリとなる特殊な NULL もあります。
これらすべての型は、PHP 内で zval と呼ばれる構造体によって統一的に表現されます。PHP ソース コードでは、この構造体の名前は「_zval_struct」です。 zval の具体的な定義は、PHP ソース コードの「Zend/zend.h」ファイルにあります。以下は、関連するコードの抜粋です。
リーリー |
ユニオン「_zvalue_value」は、PHP ですべての変数の値を表すために使用されます。ここでユニオンが使用される理由は、zval が一度に 1 つのタイプの変数しか表すことができないためです。 _zvalue_value にはフィールドが 5 つしかないことがわかりますが、PHP には NULL を含めて 8 つのデータ型があります。では、PHP は内部的に 5 つのフィールドを使用して 8 つの型をどのように表すのでしょうか。これは、PHP 設計のより賢い側面の 1 つであり、フィールドを再利用することでフィールドを削減するという目的を達成します。たとえば、PHP 内では、ブール型、整数、リソース (リソースの識別子が保存されている場合) は lval フィールドを介して保存されます。str は文字列を保存します。 PHP では配列は実際にはハッシュ テーブルです)、obj にはオブジェクトの種類が格納されます。すべてのフィールドが 0 または NULL に設定されている場合、PHP では NULL を意味するため、8 種類の値を格納するために 5 つのフィールドが使用されます。
現在のzvalの値の型(値の型は_zvalue_value)は、「_zval_struct」の型によって決まります。 _zval_struct は、C 言語での zval の特定の実装です。各 zval は変数のメモリ オブジェクトを表します。 value と type に加えて、_zval_struct には refcount__gc と is_ref__gc という 2 つのフィールドがあることがわかります。それらのサフィックスから、これら 2 つはガベージ コレクションに関連していると結論付けることができます。そうです、PHP のガベージ コレクションはこれら 2 つのフィールドに完全に依存しています。このうち、refcount__gc は、現在この zval を参照している変数がいくつかあることを示し、is_ref__gc は、現在の zval が参照によって参照されているかどうかを示します。これは、PHP の zval の「Write-On-Copy」メカニズムに関連しています。このトピックはこの記事の焦点ではないため、ここでは詳しく説明しません。読者は refcount__gc フィールドの役割だけを覚えておく必要があります。
PHP5.2 のガベージ コレクション アルゴリズム—参照カウント
PHP5.2 で使用されるメモリ再利用アルゴリズムは、有名な参照カウントです。このアルゴリズムの中国語訳は「参照カウント」と呼ばれ、その考え方は非常に直感的で簡潔です。各メモリ オブジェクトにカウンタを割り当て、カウンタを初期化します。メモリ オブジェクトが作成されたときは 1 (つまり、この時点では常にこのオブジェクトを参照する変数が存在します)、新しい変数がこのメモリ オブジェクトを参照するたびに、カウンタは 1 ずつ増加します。オブジェクトが減少すると、カウンタは 1 ずつ減ります。 ガベージの場合、リサイクル メカニズムが動作すると、カウンタが 0 のすべてのメモリ オブジェクトが破棄され、それらによって占有されていたメモリがリサイクルされます。 PHP のメモリ オブジェクトは zval、カウンタは refcount__gc です。
たとえば、次の PHP コードは、PHP5.2 カウンターの動作原理を示しています (カウンター値は xdebug.org を通じて取得されます)。
$val1 = 100; //zval(val1).refcount_gc = 1; $val2 = $val1; //zval(val1).refcount_gc = 2,zval(val2).refcount_gc = 2 (コピー時書き込みなので、現在 val2 と val1 は一緒に zval を参照します) $val2 = 200; //zval(val1).refcount_gc = 1,zval(val2).refcount_gc = 1 (val2 はここで新しい zval を作成します) unset($val1); //zval(val1).refcount_gc = 0 ($val1 によって参照される zval は使用できなくなり、GC によってリサイクルされます) ?> |
$a = 配列(); $a[] = & $a; unset($a); ?> |
クラスフー |
累積メモリ リークを引き起こす可能性のあるシナリオでは、PHP5.2 では継続的に累積メモリ リークが発生しますが、PHP5.3 ではメモリ リークを常にしきい値 (ルート バッファ サイズに関連する) 以下に制御できることがわかります。
パフォーマンスの比較についても:
クラスフー |
このスクリプトはループを 1,000,000 回実行して比較に十分な遅延時間を作成し、次に CLI を使用してメモリ リサイクルをオンおよびメモリ リサイクルをオフにしてこのスクリプトを実行します。
時間 php -dzend.enable_gc=0 -dmemory_limit=-1 -n example2.php
#そして |
ガベージコレクションアルゴリズムに関連するPHP設定
php.ini の zend.enable_gc を変更することで PHP のガベージ コレクション メカニズムをオンまたはオフにすることができます。また、gc_enable() または gc_disable() を呼び出して PHP のガベージ コレクション メカニズムをオンまたはオフにすることもできます。 PHP5.3 でガベージ コレクション メカニズムがオフになっている場合でも、PHP はルートの可能性をルート バッファーに記録しますが、ルート バッファーがいっぱいになると、PHP は自動的にガベージ コレクションを実行しません。もちろん、手動で gc_collect_cycles を呼び出すこともできます。 ( ) 関数はメモリ再利用を強制します。
この記事は表示-非営利 3.0 ライセンス契約に基づいて公開されており、転載と解釈は歓迎されますが、この記事の署名
張楊 (リンクを含む) は保持しなければならず、商業目的は許可されません。