ホームページ >バックエンド開発 >PHPの問題 >PHP ガベージ コレクションの原理を 10 分で理解する

PHP ガベージ コレクションの原理を 10 分で理解する

王林
王林オリジナル
2019-09-04 09:52:484441ブラウズ

PHP ガベージ コレクションの原理を 10 分で理解する

php のガベージ コレクション メカニズムは、PHPer にとってよく知られていますが、あまり馴染みのない内容です。では、PHP はどのようにして不要なメモリをリサイクルするのでしょうか?

php 変数のメモリ格納構造:

まず、ガベージ コレクションの原理を理解しやすくするための基礎知識を理解する必要があります。 PHP が C で書かれていることは誰もが知っているので、PHP 変数の内部ストレージ構造も C 言語、つまり zval の構造に関連します。

struct _zval_struct {
    union {
        long lval;
        double dval;
        struct {
            char *val;
            int len;
        } str;
        HashTable *ht;
        zend_object_value obj;
    } value;                    //变量value值
    zend_uint refcount__gc;   //引用计数内存中使用次数,为0删除该变量
    zend_uchar type;           //变量类型
    zend_uchar is_ref__gc;    //区分是否是引用变量
};

の内容からわかります。各php変数は、変数の型、値の値、参照カウント数、参照変数かどうかの4つの部分で構成される上記の構造です。

注: 上記のzval構造は、php5.3バージョン以降の構造です。 php5.3 より前では、新しいものは導入されておらず、ガベージ コレクション メカニズムは GC であるため、名前は _gc; ではなく、PHP7 バージョン以降は、パフォーマンスの問題により zval 構造体が書き換えられたため、ここでは説明しません。

参照カウントの原則:

PHP 変数の内部ストレージ構造を理解した後、PHP 変数の割り当てと初期のガベージ コレクション メカニズムに関連する原則について学びます。

変数コンテナ

非配列変数とオブジェクト変数

定数が変数に代入されるたびに、変数コンテナが生成されます。

例:

$a = '许铮的技术成长之路';
xdebug_debug_zval('a')

結果:

a: (refcount=1, is_ref=0)='许铮的技术成长之路'

配列変数とオブジェクト変数

は要素番号を生成します番号 1 の変数コンテナ

例:

$b = [
'name' => '许铮的技术成长之路',
'number' => 3
];
xdebug_debug_zval('b')

結果:

b: (refcount=1, is_ref=0)=array ('name' => (refcount=1, is_ref=0)='许铮的技术成长之路', 
'number' => (refcount=1, is_ref=0)=3)

代入原則 (コピーオンライト テクノロジ)

定数の代入を理解したら、メモリの観点から変数間の代入を考えてみましょう

例:

$a = [
'name' => '许铮的技术成长之路',
'number' => 3
]; //创建一个变量容器,变量a指向给变量容器,a的ref_count为1
$b = $a; //变量b也指向变量a指向的变量容器,a和b的ref_count为2
xdebug_debug_zval('a', 'b');
$b['name'] = '许铮的技术成长之路1';//变量b的其中一个元素发生改变,此时会复制出一个新的变量容器,
变量b重新指向新的变量容器,a和b的ref_count变成1
xdebug_debug_zval('a', 'b');

結果:

a: (refcount=2, is_ref=0)=array ('name' => (refcount=1, is_ref=0)='许铮的技术成长之路', 'number' => (refcount=1, is_ref=0)=3)
b: (refcount=2, is_ref=0)=array ('name' => (refcount=1, is_ref=0)='许铮的技术成长之路', 'number' => (refcount=1, is_ref=0)=3)
a: (refcount=1, is_ref=0)=array ('name' => (refcount=1, is_ref=0)='许铮的技术成长之路', 'number' => (refcount=1, is_ref=0)=3)
b: (refcount=1, is_ref=0)=array ('name' => (refcount=1, is_ref=0)='许铮的技术成长之路1', 'number' => (refcount=1, is_ref=0)=3)

つまり、変数 a が変数 b に代入されるとき、新しい変数コンテナはすぐには生成されませんが、変数 b は変数 a が指す変数コンテナを指します、つまり、メモリが「共有」されます。これは Copy on writeTechnology

参照カウントは 0

# にクリアされます##変数コンテナのref_countが0になると変数コンテナが破棄されメモリリサイクルが実現することを意味しますこれもphp5.3以前のガベージコレクションの仕組みです

例:


$a = "许铮的技术成长之路";
$b = $a;
xdebug_debug_zval('a');
unset($b);
xdebug_debug_zval('a');

結果:


a: (refcount=2, is_ref=0)='许铮的技术成长之路'
a: (refcount=1, is_ref=0)='许铮的技术成长之路'

循環参照によるメモリ リークの問題:

しかし、これは、php5.3 より前のガベージ コレクション機構の抜け穴です。つまり、オブジェクト内の配列または子要素がその親要素を参照しており、このときにその親要素が削除された場合、この変数コンテナは削除されません。これは、その子要素がまだ変数コンテナを指しているためですが、変数コンテナを指しているシンボルはクリアできないため、スクリプトの実行が終了するまでメモリ リークが発生します。

例:


$a = array( 'one' );
$a[] = &$a;
xdebug_debug_zval( 'a' );

この例では出力が適切ではないため、次の図に示すようにグラフィカル表現を使用します。

PHP ガベージ コレクションの原理を 10 分で理解する

例:

unset($a);
xdebug_debug_zval('a');

図に示すように:


PHP ガベージ コレクションの原理を 10 分で理解する

新しいガベージ コレクション メカニズム:

ルート バッファー メカニズムは、php のバージョン 5.3 以降に導入されました。つまり、php が開始されると、指定された数の zval を持つルート バッファーがデフォルトで設定されます (デフォルトは 10000)。php が循環参照 zval があることを検出すると、それがルート バッファーに置かれます。バッファが構成ファイルで指定された数 (デフォルトは 10000) に達すると、循環参照によるメモリ リークの問題を解決するためにガベージ コレクションが実行されます。

ガベージであることを確認する基準:

1. 参照カウントがゼロに減らされた場合、変数コンテナはクリア (解放) され、ガベージではなくなります。

2. zval の参照カウントが減らされても、依然として より大きい場合0 の場合、ガベージ サイクルに入ります。次に、ガベージ サイクル中に、参照カウントが 1 減らされているかどうかを確認し、どの変数コンテナの参照が 0 であるかを確認して、どの部分がガベージであるかを見つけます。

概要:

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

1. php の参照カウント メカニズムに基づいています (php5.3 より前ではこのメカニズムのみが利用可能でした)
2 、ルート バッファ メカニズムを同時に使用します。PHP は、循環参照を持つ zval があることを検出すると、それをルート バッファに置きます。ルート バッファが設定ファイルで指定された数に達すると、ガベージ コレクションが実行されます。循環参照によって引き起こされるメモリ リークの問題を解決する (php5.3 でこのメカニズムが導入され始めました)

その他の関連する質問については、PHP 中国語 Web サイトを参照してください:

php ビデオ チュートリアル

以上がPHP ガベージ コレクションの原理を 10 分で理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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