ホームページ バックエンド開発 PHPチュートリアル PHP5.3のガベージコレクション機構について

PHP5.3のガベージコレクション機構について

Jul 25, 2016 am 09:10 AM

  1. struct _zval_struct {
  2. /* 変数情報 */
  3. zvalue_value value; /* value */
  4. zend_uint refcount__gc;
  5. zend_uchar type; /* アクティブな型 */
  6. zend_uchar is_ref__gc;
  7. };
コードをコピー
PHP5.3より前のバージョンと比較すると、新しいガベージコレクション機構のために、参照カウントフィールドrefcountと参照フィールドis_refの後に__gcが追加されています。 PHP のソース コード スタイルでは、多数のマクロが非常に特徴的です。これらのマクロは、インターフェイス層に相当し、ALLOC_ZVAL マクロなど、インターフェイス層の下にある一部の実装を保護します。このマクロは、PHP のメモリ管理割り当て関数 emalloc を直接呼び出してメモリを割り当てていました。 by 変数の型とサイズが決定されます。 ガベージ コレクション メカニズムの導入後、ALLOC_ZVAL マクロは新しいガベージ コレクション ユニット構造を直接採用します。割り当てられるサイズはすべて同じであり、メモリを割り当てた後、zval_gc_info 構造によって占有されるメモリ サイズになります。この構造体は初期化されます。

  1. /* 次のマクロは、zend_alloc.h のマクロをオーバーライドします */
  2. #undef ALLOC_ZVAL
  3. #define ALLOC_ZVAL(z)
  4. do {
  5. (z) = (zval*)emalloc(sizeof(zval_gc_info));
  6. GC_ZVAL_INIT(z);
  7. } while (0)
コード
zend_gc.h ファイルは zend.h の 749 行目で参照されています: #include "zend_gc.h" により、237 行目で参照されている ALLOC_ZVAL が置き換えられますzend_alloc.h ファイル内の他のマクロ 新しいマクロでは、割り当てられたメモリ サイズと割り当て内容が変更され、以前の純粋なメモリ割り当てにすべての内容が追加されました。 zval_gc_info 構造内:

    typedef struct _zval_gc_info {
  1. zval z;
  2. union {
  3. gc_root_buffer *buffered;
  4. struct _zval_gc_info *next;
  5. } u;
  6. } コピーコード
ZVAL コンテナストレージの場合variable には zval 構造体が割り当てられます。これにより、zval 変数で割り当てられたメモリの先頭と確実に位置合わせされ、zval_gc_info 型ポインタがキャストされるときに zval として使用できるようになります。 zval フィールドの後に共用体があります: u。 u には、gc_root_buffer 構造体のバッファリングされたフィールドと zval_gc_info 構造体の次のフィールドが含まれます。 これら 2 つのフィールドの 1 つは、ガベージ コレクション メカニズムによってキャッシュされたルート ノードを表し、もう 1 つは、ガベージ コレクション メカニズムによってキャッシュされたノードがルート ノードとして使用されるかリスト ノードとして使用されるかに関係なく、zval_gc_info リスト内の次のノードを表します。ここに反映されます。 ALLOC_ZVAL は、zval を置き換える zval_gc_info を初期化するためにメモリを割り当てた後、GC_ZVAL_INIT を呼び出します。このフィールドは、ガベージ コレクション バッファーに配置される場合にのみ値を持ちます。それ以外の場合は、常に値が保持されます。 NULL にしてください。 PHP のすべての変数は zval 変数の形式で存在するため、ここでは zval_gc_info を使用して zval を置き換えることにより、ガベージ コレクション メカニズムを元のシステムに正常に統合できます。 PHP のガベージ コレクション メカニズムは PHP5.3 ではデフォルトで有効になっていますが、設定ファイルを通じて直接無効に設定できます。対応する設定フィールドは zend.enable_gc です。 デフォルトでは、php.ini ファイルにこのフィールドはありません。この機能を無効にする必要がある場合は、php.ini に zend.enable_gc=0 または zend.enable_gc=off を追加します。 php.ini 設定 zend.enable_gc を変更することに加えて、gc_enable()/gc_disable() 関数を呼び出してガベージ コレクション メカニズムをオン/オフにすることもできます。 これらの関数を呼び出す効果は、構成項目を変更してガベージ コレクション メカニズムをオンまたはオフにするのと同じです。 これら 2 つの関数に加えて、PHP にはルート バッファがいっぱいでない場合にサイクル リサイクルを強制する gc_collect_cycles() 関数が用意されています。 PHP ソース コードには、ガベージ コレクション メカニズムがオンになっているかどうかに関連する操作とフィールドがいくつかあります。 zend.c ファイルには次のコードがあります。

static ZEND_INI_MH(OnUpdateGCEnabled) /* {{{ */

{
OnUpdateBool(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
if (GC_G(gc_enabled )) {
    gc_init (TSRMLS_C);
  1. }
  2. return SUCCESS;
  3. }
  4. /* }}} */
  5. ZEND_INI_BEGIN()
  6. ZEND_INI_ENTRY("error_reporting", NULL, ZEND_INI_ALL, OnUpdateErrorReporting)
  7. STD_ZEND_INI_BOOLEAN("zend.enable_gc", "1", ZEND_INI_ALL, OnUpdateGCEnabled, gc_enabled, zend_gc_globals, gc_globals)
  8. #ifdef ZEND_MULTIBYTE
  9. STD_ZEND_INI_BOOLEAN("detect_unicode", "1", ZEND_INI_ALL, OnUpdateBool, detect_unicode, zend_compiler_globals, Compiler_globals)
  10. #endif
  11. ZEND_INI_END()
  12. コードをコピー
  13. zend.enable_gc 対応する操作関数は ZEND_INI_MH (OnUpdateGCEnabled) です。ガベージ コレクション メカニズムがオンになっている場合、つまり GC_G (gc_enabled) が true の場合、gc_init 関数が呼び出され、ガベージ コレクション メカニズムの初期化操作が実行されます。 gc_init 関数は zend/zend_gc.c の 121 行目にあります。この関数はガベージ コレクション メカニズムがオンになっているかどうかを決定します。オンになっている場合、メカニズム全体が初期化されます。つまり、割り当てのために malloc が直接呼び出されます。キャッシュ リスト全体に対して 10,000 個の gc_root_buffer メモリ スペース。 ここでの 10000 はコード内にハードコーディングされており、マクロ GC_ROOT_BUFFER_MAX_ENTRIES として存在します。この値を変更する必要がある場合は、ソース コードを変更して PHP を再コンパイルする必要があります。 gc_init 関数は、メモリの事前割り当て後に gc_reset 関数を呼び出し、メカニズム全体で使用されるいくつかのグローバル変数をリセットします。たとえば、gc 実行数 (gc_runs) や gc 内のガベージ (収集された) の数の統計を 0 に設定します。 、および二重リンクリストの先頭ノードを設定します。前のノードと次のノードはそれ自体を指します。ガベージ コレクション メカニズム用に前述したグローバル変数に加えて、他にも一般的に使用される変数があり、その一部については以下で説明します。

      typedef struct _zend_gc_globals {
    1. zend_bool gc_enabled; /* ガベージコレクションメカニズムを有効にするかどうか*/
    2. zend_bool gc_active; /* 事前に割り当てられたバッファー配列、デフォルトは 10000 (バッファーの事前割り当て配列) */
    3. gc_root_buffer root; /* サイクルの可能なルートのリスト */
    4. gc_root_buffer *unused; /* 未使用のバッファーのリスト */
    5. gc_root_buffer *first_unused; /* 最初へのポインター未使用のバッファ ノード (最初の未使用のバッファへのポインタ) */
    6. gc_root_buffer *last_unused; /* 最後の未使用のバッファ ノードへのポインタ、この最後の未使用のバッファへのポインタ */
    7. zval_gc_info *zval_to_free; /* 解放する zval の一時リスト */
    8. zval_gc_info *free_list; /* 一時変数、必須 解放されたリストの先頭 */
    9. zval_gc_info *next_to_free; /* 一時変数、次に解放される変数の場所 */
    10. zend_uint gc_runs; /* gc 実行数の統計*/
    11. zend_uintcollected; /* gc 内のガベージの数 */
    12. // 省略...
    13. }
    14. コードをコピー
    unset 操作を使用して、この変数によって占有されているメモリをクリアするとき (おそらく単にデクリメントするだけ)参照カウントを 1 つ増やします)、現在のシンボルのハッシュからになります。テーブルから変数名に対応する項目を削除します。すべての操作が実行された後、シンボル テーブルから削除された項目に対してデストラクターが呼び出されます。は zval_dtor を呼び出し、一般変数は zval_ptr_dtor を呼び出します。 もちろん、unset 関数は言語構造であるため、PHP の関数セットには見つかりません。 対応する中間コードは ZEND_UNSET で、関連する実装は Zend/zend_vm_execute.h ファイルにあります。 zval_ptr_dtor は関数ではなく、関数に少し似た単なるマクロです。 Zend/zend_variables.h ファイルでは、このマクロは関数 _zval_ptr_dtor を指します。 Zend/zend_execute_API.c の 424 行目では、関数関連のコードは次のとおりです。

    ZEND_API void _zval_ptr_dtor(zval **zval_ptr ZEND_FILE_LINE_DC) /* {{{ */
      {
    1. #if DEBUG_ZEND>=2
    2. printf("%x (%x) の参照カウントを削減しています: %d-> ;%DN ", *ZVAL_PTR, ZVAL_PTR, Z_REFCOUNT_PP (ZVAL_PTR), Z_REFCOUNT_PP (ZVAL_PTR) - 1); Fcount_pp (zval_ptr) == 0) {
    3. TSRMLS_FETCH ();
    4. if (*zval_ptr != &EG(uninitialized_zval)) {
    5. GC_REMOVE_ZVAL_FROM_BUFFER(*zval_ptr);
    6. zval_dtor(*zval_ptr);
    7. efree_rel(*zval_ptr);
    8. }
    9. } else {
    10. TSRMLS_FETCH();
    11. if (Z_RE FCOUNT_PP(zval_ptr ) == 1) {
    12. Z_ UNSET_ISREF_PP(zval_ptr) ;
    13. }
    14. GC_ZVAL_CHECK_POSSIBLE_ROOT(*zval_ptr);
    15. }
    16. }
    17. /* }}} */
    18. コードをコピー
    19. コードから、この zval の破棄プロセスが明確にわかります。次の 2 つの操作が参照カウント フィールドに対して実行されます。 変数の参照カウントが 1 の場合、つまり参照カウントが 1 減算されて 0 になった場合、変数は直接クリアされます。現在の変数がキャッシュされている場合、変数の参照カウントが 1 より大きい場合、つまり、1 を引いた後の参照カウントが 0 より大きい場合、変数はガベージ リストに入れられます。変更に参照がある場合は、その参照を削除します。

      変数をガベージ リストに入れる操作は GC_ZVAL_CHECK_POSSIBLE_ROOT で、これもマクロで関数 gc_zval_check_possible_root に対応しますが、この関数は配列とオブジェクトに対してガベージ コレクション操作のみを実行します。配列変数とオブジェクト変数の場合は、gc_zval_possible_root 関数を呼び出します。

      1. ZEND_API void gc_zval_possible_root(zval *zv TSRMLS_DC)
      2. {
      3. if (UNEXPECTED(GC_G(free_list) != NULL &&
      4. GC_ZVAL_ADDRESS(zv) != NULL &&
      5. GC_ZVAL_GET_COL OR(zv) == GC_BLACK) &&
      6. (GC_ZVAL_ADDRESS(zv) < GC_G(buf) ||
      7. GC_ZVAL_ADDRESS(zv) >= GC_G(last_unused))) {
      8. /* 指定された zval は、
      9. * 現在実行中の GC によって削除される予定のガベージです* /
      10. return;
      11. }
      12. if (zv->type == IS_OBJECT) {
      13. GC_ZOBJ_CHECK_POSSIBLE_ROOT(zv);
      14. return;
      15. }
      16. GC_BENCH_INC(zval_possible_root);
      17. if (GC_ZVAL_GET_COLOR(zv) != GC_ RPLE) {
      18. GC_ZVAL_SET_PURPLE (zv);
      19. if (!GC_ZVAL_ADDRESS(zv)) {
      20. gc_root_buffer *newRoot = GC_G(未使用);
      21. if (newRoot) {
      22. GC_G(未使用) = newRoot->prev;
      23. } else if (GC_G (first_unused ) != GC_G(last_unused)) {
      24. newRoot = GC_G(first_unused);
      25. GC_G(first_unused)++;
      26. } else {
      27. if (!GC_G(gc_enabled)) {
      28. GC_ZVAL_SET_BLACK(zv);
      29. return;
      30. }
      31. Zv-&gt; refcount__gc ++;
      32. gc_collect_cycles(tsrmls_c);
      33. GC _G (未使用) = newRoot->prev;
      34. }
      35. newRoot->next = GC_G(roots).next;
      36. newRoot->prev = &GC_G(roots);
      37. GC_G(roots).next-> ;prev = newRoot;
      38. GC_G(roots).next = newRoot;
      39. GC_ZVAL_SET_ADDRESS(zv, newRoot);
      40. newRoot->ハンドル = 0;
      41. newRoot->u.pz = zv;
      42. GC_BENCH_INC(zval_buffered);
      43. GC_BENCH_INC(root_buf _length );
      44. GC_BENCH_PEAK(root_buf_peak, root_buf_length);
      45. }
      46. }
      47. }
      48. コードをコピー
      49. 前述したように、gc_zval_check_possible_root 関数は配列とオブジェクトに対してのみガベージ コレクション操作を実行します。ただし、gc_zval_possible_root 関数では、オブジェクト型の変数に対して GC_ZOBJ_CHECK_POSSIBLE_ROOT マクロが呼び出されます。ガベージ コレクション メカニズムに使用できる他の変数タイプの場合、呼び出しプロセスは次のとおりです。 zval ノード情報がノード バッファーに入れられているかどうかを確認し、ノード バッファーに入れられている場合は、直接返すことでパフォーマンスを最適化できます。 次に、オブジェクト ノードを処理し、その後の操作を実行せずに直接戻り、ノードが紫色にマークされているかどうかを確認します。これは、ノードが 1 回だけ追加されるようにするためです。 . バッファー操作。

        ノードの色を紫としてマークします。これは、ノードがバッファに追加されており、次回追加する必要がないことを示します。 新しいノードの場所を見つけて、バッファーがいっぱいの場合はガベージ コレクションを実行します。 バッファが配置されている二重リンクリストに新しいノードを追加します。 gc_zval_possible_root 関数では、バッファがいっぱいになると、プログラムは gc_collect_cycles 関数を呼び出してガベージ コレクション操作を実行します。 最も重要な手順は次のとおりです。 行 628 は、公式ドキュメントのアルゴリズムのステップ B です。このアルゴリズムは、深さ優先検索を使用してすべての可能なルートを見つけた後、各変数コンテナーの参照カウントを 1 ずつ減分します。デクリメントされていない 2 つの「1」が 1 減算された灰色のマークでマークされます。 629 行目 これはアルゴリズムのステップ C で、アルゴリズムは再び各ルート ノードに対して深さ優先検索を使用し、各変数コンテナの参照カウントをチェックします。 参照カウントが 0 の場合、変数コンテナーは白でマークされます。参照カウントが 0 より大きい場合は、深さ優先検索を使用してこの時点で参照カウントを減分 (つまり、参照カウントを 1 ずつ増やし) した操作を再開し、それらを黒で再マークします。 630 行目 アルゴリズムの最後のステップ D では、アルゴリズムはルート バッファーを走査してそこから変数コンテナー ルート (zval ルート) を削除し、同時に、前のステップで白とマークされた変数コンテナーがあるかどうかを確認します。 。白でマークされた各変数コンテナはクリアされます。 [gc_collect_cycles() -> gc_collect_roots() -> zval_collect_white() ] では、白でマークされたノードがグローバル変数 zval_to_free リストに追加されることがわかります。このリストは後で使用します。 PHP のガベージ コレクション メカニズムは、実行中にステータスを 4 色でマークします。 GC_WHITE 白はゴミを意味します GC_PURPLE 紫はバッファに入れられたことを意味します GC_GREY 灰色は、refcount を 1 つ減らす操作が実行されたことを示します GC_BLACK 黒はデフォルトの色で、通常の色です。 関連するタグとオペレーションコードは次のとおりです。

        1. #define GC_COLOR 0x03
        2. #define GC_BLACK 0x00
        3. #define GC_WHITE 0x01
        4. #define GC_GREY 0x02
        5. #define GC_PURPLE 0x03
        6. #define GC_ADDRESS(v )
        7. ((gc_root_buffer*)((zend_uintptr_t)(v ) ) & ~GC_COLOR))
        8. #define GC_SET_ADDRESS(v, a)
        9. (v) = ((gc_root_buffer*)((((zend_uintptr_t)(v)) & GC_COLOR) | ((zend_uintptr_t)(a)))
        10. #define GC_GET_COLOR(v)
        11. (((zend_uintptr_t)(v)) & GC_COLOR)
        12. #define GC_SET_COLOR(v, c)
        13. (v) = ((gc_root_buffer*)((((zend_uintptr_t)(v)) & ~ GC_COLOR) | (c)))
        14. #define GC_SET_BLACK(v)
        15. (v) = ((gc_root_buffer*)((zend_uintptr_t)(v)) & ~GC_COLOR))
        16. #define GC_SET_PURPLE(v)
        17. (v ) = ((gc_root_buffer*)((zend_uintptr_t)(v)) | GC_PURPLE))
        コードをコピー

        上記のビットでステータスをマークする方法は、PHP ソース コードでより頻繁に使用されます。メモリ管理で使用されます。 、など。これは比較的効率的で経済的な解決策です。ただし、データベースを設計するときは、このメソッドをフィールドに使用できない場合があります。より直感的で読みやすい方法で実装する必要があります。



このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Laravelでフラッシュセッションデータを使用します Laravelでフラッシュセッションデータを使用します Mar 12, 2025 pm 05:08 PM

Laravelは、直感的なフラッシュメソッドを使用して、一時的なセッションデータの処理を簡素化します。これは、アプリケーション内に簡単なメッセージ、アラート、または通知を表示するのに最適です。 データは、デフォルトで次の要求のためにのみ持続します。 $リクエスト -

PHPのカール:REST APIでPHPカール拡張機能を使用する方法 PHPのカール:REST APIでPHPカール拡張機能を使用する方法 Mar 14, 2025 am 11:42 AM

PHPクライアントURL(CURL)拡張機能は、開発者にとって強力なツールであり、リモートサーバーやREST APIとのシームレスな対話を可能にします。尊敬されるマルチプロトコルファイル転送ライブラリであるLibcurlを活用することにより、PHP Curlは効率的なexecuを促進します

Laravelテストでの簡略化されたHTTP応答のモッキング Laravelテストでの簡略化されたHTTP応答のモッキング Mar 12, 2025 pm 05:09 PM

Laravelは簡潔なHTTP応答シミュレーション構文を提供し、HTTP相互作用テストを簡素化します。このアプローチは、テストシミュレーションをより直感的にしながら、コード冗長性を大幅に削減します。 基本的な実装は、さまざまな応答タイプのショートカットを提供します。 Illuminate \ support \ facades \ httpを使用します。 http :: fake([[ 'google.com' => 'hello world'、 'github.com' => ['foo' => 'bar']、 'forge.laravel.com' =>

Codecanyonで12の最高のPHPチャットスクリプト Codecanyonで12の最高のPHPチャットスクリプト Mar 13, 2025 pm 12:08 PM

顧客の最も差し迫った問題にリアルタイムでインスタントソリューションを提供したいですか? ライブチャットを使用すると、顧客とのリアルタイムな会話を行い、すぐに問題を解決できます。それはあなたがあなたのカスタムにより速いサービスを提供することを可能にします

PHPにおける後期静的結合の概念を説明します。 PHPにおける後期静的結合の概念を説明します。 Mar 21, 2025 pm 01:33 PM

記事では、PHP 5.3で導入されたPHPの後期静的結合(LSB)について説明し、より柔軟な継承を求める静的メソッドコールのランタイム解像度を可能にします。 LSBの実用的なアプリケーションと潜在的なパフォーマ

フレームワークのカスタマイズ/拡張:カスタム機能を追加する方法。 フレームワークのカスタマイズ/拡張:カスタム機能を追加する方法。 Mar 28, 2025 pm 05:12 PM

この記事では、フレームワークにカスタム機能を追加し、アーキテクチャの理解、拡張ポイントの識別、統合とデバッグのベストプラクティスに焦点を当てています。

フレームワークセキュリティ機能:脆弱性から保護します。 フレームワークセキュリティ機能:脆弱性から保護します。 Mar 28, 2025 pm 05:11 PM

記事では、入力検証、認証、定期的な更新など、脆弱性から保護するためのフレームワークの重要なセキュリティ機能について説明します。

See all articles