PHPのガベージコレクションの仕組みを詳しく解説_PHPチュートリアル

WBOY
リリース: 2016-07-13 10:10:07
オリジナル
1020 人が閲覧しました

PHPのガベージコレクションの仕組みを詳しく解説

最近、PHP を使用してデーモン プロセスの実装をシミュレートするスクリプトを作成したため、PHP のガベージ コレクション メカニズムを深く理解する必要があります。この記事は PHP マニュアルを参照しています。
PHP のガベージ コレクション メカニズム (GC) を理解する前に、まず変数のストレージについて理解してください。
phpの変数はzval変数コンテナに存在します。構造は次のとおりです:
タイプ
価値
is_ref
参照カウント
zval には、変数の型と値を保存するだけでなく、is_ref フィールドと refcount フィールドもあります。
is_ref: これはブール値であり、変数が参照セットに属しているかどうかを区別するために使用されます。これはどういう意味ですか? これは、変数に複数のエイリアスがあるかどうかを示す、と考えることができます。
refcount: この zval 変数コンテナーを指す変数の数を示すカウンター。
両者の間にはデフォルトの関係があります。refcount 値が 1 の場合、is_ref の値は false です。 refcount が 1 であるため、この変数は複数の別名を持つことができず、参照はありません。
xdebug 拡張機能をインストールした後、xdebug_debug_zval を使用して zval コンテナーの詳細を出力できます。
ここで注意すべき点は、変数 = を別の変数に代入する場合、メモリ空間は新しい変数にすぐには割り当てられませんが、元の変数の zval の refcount に 1 が追加されることです。 元の変数が変更された場合にのみ、新しい変数にメモリ領域が割り当てられ、元の変数の refcount が 1 減らされます。もちろん、元の変数の設定を解除すると、新しい変数は再割り当てするのではなく、元の変数の zval を直接使用します。
& が参照によって代入されると、元の変数の is_ref が 1 になり、refcount が 1 ずつ増加します。変数 & に値を代入すると、先に = で代入された変数がスペースを割り当てます。
$a = 1;
xdebug_debug_zval('a');
エコー PHP_EOL;
$b = $a;
xdebug_debug_zval('a');
エコー PHP_EOL;
$c = &$a;
xdebug_debug_zval('a');
エコー PHP_EOL;
xdebug_debug_zval('b');
エコー PHP_EOL;
?>
実行結果は次のとおりです:
a:(refcount=1, is_ref=0),int 1
a:(refcount=2, is_ref=0),int 1
a:(refcount=2, is_ref=1),int 1
b:(refcount=1, is_ref=0),int 1
上記の zval はスカラーを格納しますが、複合型の配列はどのように格納されるのでしょうか?
$a = array( '意味' => '人生', '数値' => 42 );
xdebug_debug_zval( 'a' );
エコー PHP_EOL;
クラステスト{
パブリック $a = 1;
パブリック $b = 2;
関数ハンドル(){
エコー「へへ」;
}
}
$test = 新しいテスト();
xdebug_debug_zval('テスト');
?>
実行結果は次のとおりです:
a:(refcount=1, is_ref=0),
配列
'意味' => (refcount=1, is_ref=0),
文字列
「人生」(長さ=4)
'数値' => (refcount=1, is_ref=0),
int
42
テスト:(refcount=1, is_ref=0),
オブジェクト(テスト)[1]
public 'a' => (refcount=2, is_ref=0),
int
1
public 'b' => (refcount=2, is_ref=0),
int
2
配列が配列の長さよりも 1 つ多い zval ストレージを使用していることがわかります。オブジェクトも似ています。配列のストレージ表現を以下に示します
ご覧のとおり、配列には 3 つの zval コンテナが割り当てられています: 意味する数字
それでは、いわゆる循環参照がどのように生成されるかを見てみましょう
$a = array( 'one' );
$a[] =& $a;
xdebug_debug_zval( 'a' );
?>
実行結果:
a:(refcount=2, is_ref=1),
配列
0 => (refcount=1, is_ref=0),
文字列
「1」(長さ=3)
1 => (refcount=2, is_ref=1)、&array
a は 1 と同じ zval コンテナです。以下の通り:
これは循環参照を形成します。
PHP 5.2 以前のバージョンには、特別なガベージ コレクター GC (ガベージ コレクション) がありません。エンジンは、変数空間を解放できるかどうかを判断するときに、変数の zval の refcount の値に依存します (refcount が 0 の場合)。場合は変数空間を解放できますが、それ以外の場合は解放されません。これは非常に単純な GC 実装です。
設定を解除すると ($a)、配列の refcount が 1 減って 1 になります。この zval を指す変数はなくなり、この zval のカウンターは 1 になり、リサイクルされません。
この構造体 (つまり、変数コンテナー) を指すスコープ内にシンボルはなくなりましたが、配列要素 "1" は依然として配列自体を指しているため、このコンテナーをクリアすることはできません。他にそれを指すシンボルがないため、ユーザーは構造体をクリアする方法がなく、メモリ リークが発生します。幸いなことに、PHP はリクエストの最後にこのデータ構造をクリアしますが、PHP がデータ構造をクリアする前に、メモリ内の大量のスペースを消費します。これは、解析アルゴリズムを実装している場合、または子要素がその親を指すようにするなどの他の作業を行っている場合によく発生します。もちろん、同じ状況がオブジェクトでも発生する可能性があります。実際、オブジェクトは常に暗黙的に参照されるため、オブジェクトで発生する可能性が高くなります。
上記の状況が 1 回か 2 回だけ発生する場合は問題ありませんが、メモリ リークが数千回、さらには数十万回発生した場合、これは明らかに大きな問題です。長時間実行されるスクリプトを実行すると、要求時にデーモンがほとんど終了しないなどの問題が発生する可能性があり、メモリ領域が消費され続け、メモリ不足によるクラッシュが発生します。
PHP5.3では、特別なアルゴリズム(より複雑)が使用されます。 、循環参照によって引き起こされるメモリ リークの問題に対処します。
zval がガベージである可能性がある場合、コレクション アルゴリズムは zval をメモリ バッファーに置きます。バッファーが最大臨界値 (最大値は設定可能) に達すると、リサイクル アルゴリズムはバッファー内のすべての zval を循環して、それらがガベージであるかどうかを判断し、解放処理を実行します。または、スクリプトで gc_collect_cycles を使用して、バッファ内のガベージを強制的にリサイクルします。
php5.3のGCでは、ガベージは次のように説明されています:
1: zval の refcount が増加する場合、この zval はまだ使用されており、間違いなくガベージではなく、バッファーには入りません
2: zval の refcount が 0 に減らされた場合、zval は GC によって処理されるガベージ オブジェクトではないため、バッファに入りません。
3: zval の refcount が削減後に 0 より大きい場合、zval は解放できず、zval はガベージになり、バッファーに置かれる可能性があります。 PHP5.3のGCはこのようなzval処理を対象としています。
ガベージコレクションメカニズムは、PHP 設定を変更することでオン/オフにすることができます。また、gc_enable() と gc_disable() を使用してプログラム内でオン/オフを切り替えることもできます。
ガベージ コレクション メカニズムをオンにすると、メモリ リークが発生した場合に大量のメモリ領域を節約できます。ただし、ガベージ コレクション アルゴリズムの実行には時間がかかるため、ガベージ コレクション アルゴリズムをオンにするとスクリプトの実行時間が長くなります。 。
以下はPHPマニュアルに記載されているスクリプトです
クラスフー
{
パブリック $var = '3.1415962654';
}
$baseMemory =memory_get_usage();
for ( $i = 0; $i
{
$a = 新しい Foo;
$a->self = $a;
if ( $i % 500 === 0 )
{
echo sprintf( '%8d: ', $i )、memory_get_usage() - $baseMemory, "n";
}
}
?>
このスクリプトの php5.2 および 5.3 でのメモリ使用量は、以下に示すように示されています。
次のスクリプトの場合
クラスフー
{
パブリック $var = '3.1415962654';
}
for ( $i = 0; $i
{
$a = 新しい Foo;
$a->self = $a;
}
echomemory_get_peak_usage(), "n";
?>
ガベージコレクションメカニズムがオンになっている場合、スクリプトの実行時間はオンになっていない場合に比べて 7% 増加します
通常、PHP のガベージ コレクション メカニズムは、リサイクル アルゴリズムが実際に実行されているときに消費時間を増加させるだけです。ただし、通常の (小規模な) スクリプトでは、パフォーマンスへの影響はまったくありません。

www.bkjia.comtru​​ehttp://www.bkjia.com/PHPjc/938943.html技術記事 PHP のガベージ コレクション メカニズムの詳細な説明 最近、PHP を使用してデーモン プロセスの実装をシミュレートするスクリプトを作成したため、PHP のガベージ コレクション メカニズムを深く理解する必要があります。この記事は...
を参照しています
関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!