ホームページ  >  記事  >  バックエンド開発  >  PHP7 ガベージ コレクション メカニズム (GC) の分析

PHP7 ガベージ コレクション メカニズム (GC) の分析

Guanhui
Guanhui転載
2020-05-20 11:17:575654ブラウズ

PHP7 ガベージ コレクション メカニズム (GC) の分析

#ガベージ コレクション メカニズム

ガベージ コレクション メカニズムは、動的なストレージ割り当てスキームです。プログラムで不要になった割り当てられたメモリ ブロックを自動的に解放します。メモリを自動的に再利用するプロセスは、ガベージ コレクションと呼ばれます。ガベージ コレクション メカニズムにより、プログラマはプログラム メモリの割り当てについてあまり心配する必要がなく、ビジネス ロジックにより多くのエネルギーを注ぐことができます。現在人気のあるさまざまな言語の中で、ガベージ コレクション メカニズムは新世代の言語に共通の機能です。

ガベージの生成

PHP7 の文字列、配列、オブジェクトなどの複合型には、ヘッダーに gc が付いています。ガベージ コレクションをサポートするために使用されます。変数の代入や転送を行うと値の参照番号が増加し、変数の設定解除や復帰などにより変数が解放されると参照番号が減算され、減算後refcountが0になった場合は、値の参照番号が減算されます。これが変数の基本的なリサイクルプロセスです。

しかし、このメカニズムでは解決できない問題が 1 つあります。それは、循環参照の問題です。

循環参照とは何ですか?簡単に言うと、変数内に格納された値は変数自体を指します。この比較は、配列型およびオブジェクト型の変数でよく発生します。

最初に参照、つまり zend_reference 型について話しましょう。これは PHP7 の新しい変数型です。変数に対して "&" 演算が使用されると、新しい中間構造体 zend_reference が作成されます。構造体は実際には、対応する値構造体を指します。

例:

// 当进行如下赋值操作时
$a = 'hello'; // $a -> zend_string
$b = $a; // $b,$a -> zend_string
$c = &$b; // $c,$b -> zval(type = IS_REFERENCE, refcount = 2) -> zend_string

は最終的に次のようになります:

PHP7 ガベージ コレクション メカニズム (GC) の分析

つまり、$b と $c の zval は通過します。中央の構造体 zend_reference は最後の zend_string を指します。

循環参照の問題に戻り、配列循環参照の例を次に示します。

$a = [1];
$a[] = &$a;
unset($a);

& 演算を使用した後、変数 a は参照型になり、参照カウント refcount は 2 になります。そして値が代入されます。それ自体の内部の要素、つまり変数 a はそれ自体への参照になります。

詳細は次のとおりです。

PHP7 ガベージ コレクション メカニズム (GC) の分析

設定を解除すると、次の図のようになります。

PHP7 ガベージ コレクション メカニズム (GC) の分析

つまり、$a が配置されている zval 型は IS_UNDEF になり、zend_reference 構造体の参照カウントは 1 減りますが、まだ 0 より大きく、このとき構造体のこの部分はゴミになります。これは処理されないため、メモリ リークが発生する可能性があります。ここでは、この部分をバッファに収集してリサイクルするガベージ コレクターが必要です。

リサイクル プロセス

変数を削減したときに変数の refcount が 0 より大きい場合、PHP はこの変数に対してガベージの識別とリサイクルをすぐには実行しませんが、 put a バッファ内で、バッファがいっぱいになった後 (値が 10000 個)、均一に処理されます。バッファに追加されるのは、変数 zend_value の gc です。現在、ガベージは配列とオブジェクトの 2 種類にのみ発生します。配列の場合は、紹介したようにオブジェクトの場合はメンバ属性がオブジェクトそのものを参照しますが、それ以外の型では変数内のメンバが変数そのものを参照することは発生しないため、ガベージコレクションのみの処理となります。これら 2 種類の変数です。

gc zend_refcounted_h の構造は次のとおりです:

typedef struct _zend_refcounted_h {
    uint32_t         refcount; // 记录 zend_value 的引用数
    union {
        struct {
            zend_uchar    type,  // zend_value的类型, 与zval.u1.type一致
            zend_uchar    flags, 
            uint16_t      gc_info // GC信息,记录在 gc 池中的位置和颜色,垃圾回收的过程会用到
        } v;
        uint32_t type_info;
    } u;
} zend_refcounted_h;

変数はバッファに 1 回しか追加できません。繰り返しの追加を防ぐために、zend_refcounted_h.gc_info は、追加後に GC_PURPLE に設定されます。紫色でマークされた変数が追加され、今後繰り返し挿入されることはありません。

ガベージ バッファは双方向のリンク リストです。バッファがいっぱいになると、ガベージ チェック プロセスが開始されます。バッファを走査し、現在の変数のすべてのメンバーを走査してから、変数の refcount を減らします。メンバーを 1 ずつ増やして (メンバーがまだサブメンバーを含んでいる場合は、再帰的に走査 (つまり、深さ優先走査) され、最後に現在の変数の参照がチェックされます。0 に減らされた場合は、 、ゴミです。このアルゴリズムの中心原理は、ガベージはメンバ自身を参照することによって発生するため、すべてのメンバへの参照を減らします。最終変数自体の refcount が 0 になることが判明した場合、そのすべての参照はその変数自体から来ていることを意味します。使用しなくなった場合はゴミとなり、リサイクルする必要があります。それ以外の場合は、それがガベージではないため、バッファから削除する必要があることを意味します。具体的なプロセスは次のとおりです。

(1) バッファー リンク リストのルートから走査を開始し、現在の値をグレーとしてマークし (zend_refcounted_h.gc_info が GC_GREY に設定されます)、深さ優先の走査を実行します。現在の値のメンバーの数。メンバー値の参照カウントは 1 減らされ、灰色でマークされます。

(2) バッファのリンクされたリストを繰り返し走査し、現在の値の参照が 0 であるかどうかを確認します。0 であれば、それは実際にガベージであることを意味します。白 (GC_WHITE) としてマークします。0 でない場合は、除外します。自身のメンバーからの参照はすべて存在します。おそらく、外部参照があり、ゴミではないことを意味します。このとき、手順 (1) でメンバーの refcount が 1 減らされているため、再度復元する必要があります。すべてのメンバーの深い走査が実行され、メンバーの refcount が 1 だけ増加し、Black としてマークされます;

(3) バッファー リンク リストを再度走査し、ルート リンク リストから GC_WHITE 以外のノードを削除します。すべてのルートのリンクされたリストは実際のゴミであり、最終的にゴミはクリアされます。

推奨チュートリアル: "PHP7" "PHP チュートリアル"

以上がPHP7 ガベージ コレクション メカニズム (GC) の分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はlearnku.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。