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

  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_ZVAL_ADDRESS(zv) >= GC_G(last_unused))) {
      7. /* 指定された zval は、
      8. * 現在実行中の GC によって削除される予定のガベージです* /
      9. return;
      10. }
      11. if (zv->type == IS_OBJECT) {
      12. GC_ZOBJ_CHECK_POSSIBLE_ROOT(zv);
      13. return;
      14. }
      15. GC_BENCH_INC(zval_possible_root);
      16. if (GC_ZVAL_GET_COLOR(zv) != GC_ RPLE) {
      17. GC_ZVAL_SET_PURPLE (zv);
      18. if (!GC_ZVAL_ADDRESS(zv)) {
      19. gc_root_buffer *newRoot = GC_G(未使用);
      20. if (newRoot) {
      21. GC_G(未使用) = newRoot->prev;
      22. } else if (GC_G (first_unused ) != GC_G(last_unused)) {
      23. newRoot = GC_G(first_unused);
      24. GC_G(first_unused)++;
      25. } else {
      26. if (!GC_G(gc_enabled)) {
      27. GC_ZVAL_SET_BLACK(zv);
      28. return;
      29. }
      30. Zv-> refcount__gc ++;
      31. gc_collect_cycles(tsrmls_c);
      32. GC _G (未使用) = newRoot->prev;
      33. }
      34. newRoot->next = GC_G(roots).next;
      35. newRoot->prev = &GC_G(roots);
      36. GC_G(roots).next-> ;prev = newRoot;
      37. GC_G(roots).next = newRoot;
      38. GC_ZVAL_SET_ADDRESS(zv, newRoot);
      39. newRoot->ハンドル = 0;
      40. newRoot->u.pz = zv;
      41. GC_BENCH_INC(zval_buffered);
      42. GC_BENCH_INC(root_buf _length );
      43. GC_BENCH_PEAK(root_buf_peak, root_buf_length);
      44. }
      45. }
      46. }
      47. コードをコピー
      48. 前述したように、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 までご連絡ください。
PHPセッションを失敗させる可能性のあるいくつかの一般的な問題は何ですか?PHPセッションを失敗させる可能性のあるいくつかの一般的な問題は何ですか?Apr 25, 2025 am 12:16 AM

PHPSESSIONの障害の理由には、構成エラー、Cookieの問題、セッションの有効期限が含まれます。 1。構成エラー:正しいセッションをチェックして設定します。save_path。 2.Cookieの問題:Cookieが正しく設定されていることを確認してください。 3.セッションの有効期限:セッションを調整してください。GC_MAXLIFETIME値はセッション時間を延長します。

PHPでセッション関連の問題をどのようにデバッグしますか?PHPでセッション関連の問題をどのようにデバッグしますか?Apr 25, 2025 am 12:12 AM

PHPでセッションの問題をデバッグする方法は次のとおりです。1。セッションが正しく開始されるかどうかを確認します。 2.セッションIDの配信を確認します。 3.セッションデータのストレージと読み取りを確認します。 4.サーバーの構成を確認します。セッションIDとデータを出力し、セッションファイルのコンテンツを表示するなど、セッション関連の問題を効果的に診断して解決できます。

session_start()が複数回呼び出されるとどうなりますか?session_start()が複数回呼び出されるとどうなりますか?Apr 25, 2025 am 12:06 AM

session_start()への複数の呼び出しにより、警告メッセージと可能なデータ上書きが行われます。 1)PHPは警告を発し、セッションが開始されたことを促します。 2)セッションデータの予期しない上書きを引き起こす可能性があります。 3)session_status()を使用してセッションステータスを確認して、繰り返しの呼び出しを避けます。

PHPでセッションのライフタイムをどのように構成しますか?PHPでセッションのライフタイムをどのように構成しますか?Apr 25, 2025 am 12:05 AM

PHPでのセッションライフサイクルの構成は、session.gc_maxlifetimeとsession.cookie_lifetimeを設定することで達成できます。 1)session.gc_maxlifetimeサーバー側のセッションデータのサバイバル時間を制御します。 0に設定すると、ブラウザが閉じているとCookieが期限切れになります。

セッションを保存するためにデータベースを使用することの利点は何ですか?セッションを保存するためにデータベースを使用することの利点は何ですか?Apr 24, 2025 am 12:16 AM

データベースストレージセッションを使用することの主な利点には、持続性、スケーラビリティ、セキュリティが含まれます。 1。永続性:サーバーが再起動しても、セッションデータは変更されないままになります。 2。スケーラビリティ:分散システムに適用され、セッションデータが複数のサーバー間で同期されるようにします。 3。セキュリティ:データベースは、機密情報を保護するための暗号化されたストレージを提供します。

PHPでカスタムセッション処理をどのように実装しますか?PHPでカスタムセッション処理をどのように実装しますか?Apr 24, 2025 am 12:16 AM

PHPでのカスタムセッション処理の実装は、SessionHandlerInterfaceインターフェイスを実装することで実行できます。具体的な手順には、次のものが含まれます。1)CussentsessionHandlerなどのSessionHandlerInterfaceを実装するクラスの作成。 2)セッションデータのライフサイクルとストレージ方法を定義するためのインターフェイス(オープン、クローズ、読み取り、書き込み、破壊、GCなど)の書き換え方法。 3)PHPスクリプトでカスタムセッションプロセッサを登録し、セッションを開始します。これにより、データをMySQLやRedisなどのメディアに保存して、パフォーマンス、セキュリティ、スケーラビリティを改善できます。

セッションIDとは何ですか?セッションIDとは何ですか?Apr 24, 2025 am 12:13 AM

SessionIDは、ユーザーセッションのステータスを追跡するためにWebアプリケーションで使用されるメカニズムです。 1.ユーザーとサーバー間の複数のインタラクション中にユーザーのID情報を維持するために使用されるランダムに生成された文字列です。 2。サーバーは、ユーザーの複数のリクエストでこれらの要求を識別および関連付けるのに役立つCookieまたはURLパラメーターを介してクライアントに生成および送信します。 3.生成は通常、ランダムアルゴリズムを使用して、一意性と予測不可能性を確保します。 4.実際の開発では、Redisなどのメモリ内データベースを使用してセッションデータを保存してパフォーマンスとセキュリティを改善できます。

ステートレス環境(APIなど)でセッションをどのように処理しますか?ステートレス環境(APIなど)でセッションをどのように処理しますか?Apr 24, 2025 am 12:12 AM

APIなどのステートレス環境でのセッションの管理は、JWTまたはCookieを使用して達成できます。 1。JWTは、無国籍とスケーラビリティに適していますが、ビッグデータに関してはサイズが大きいです。 2.cookiesはより伝統的で実装が簡単ですが、セキュリティを確保するために慎重に構成する必要があります。

See all articles

ホット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衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

SecLists

SecLists

SecLists は、セキュリティ テスターの究極の相棒です。これは、セキュリティ評価中に頻繁に使用されるさまざまな種類のリストを 1 か所にまとめたものです。 SecLists は、セキュリティ テスターが必要とする可能性のあるすべてのリストを便利に提供することで、セキュリティ テストをより効率的かつ生産的にするのに役立ちます。リストの種類には、ユーザー名、パスワード、URL、ファジング ペイロード、機密データ パターン、Web シェルなどが含まれます。テスターはこのリポジトリを新しいテスト マシンにプルするだけで、必要なあらゆる種類のリストにアクセスできるようになります。

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

Eclipse を SAP NetWeaver アプリケーション サーバーと統合します。

SublimeText3 Linux 新バージョン

SublimeText3 Linux 新バージョン

SublimeText3 Linux 最新バージョン

SublimeText3 Mac版

SublimeText3 Mac版

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