# PHP 処理系の garbage collection を理解する メモリはいつ解放されるのか はじめに メモリ コンピュータの一時データ置き場 メモリの容量は増え続けている 無限ではない 使い果たすと... プロセスの強制終了 極端なパフォーマンスの低下 メモリ管理 必要なメモリを確保する 不要なメモリを解放する メモリの「確保」割り当て このサイズのメモリが必要です メモリの「解放」 ここのメモリは不要になりました メモリ管理は難しい メモリリーク 解放すべきメモリ領域を解放していない double free 解放済みのメモリ領域をまた解放した use-after-free 解放済みのメモリ領域にアクセスした buffer overflow 確保したメモリ領域を越えてアクセスした PHP でメモリ管理を直接おこなう必要はない Garbage Collection (GC) メモリ管理の自動化 自動でメモリを解放 PHP の GC 参照カウント + マークアンドスイープ 参照カウント 参照されている数を数える ゼロになったら解放する $a = ["foo"]; $b = ["bar"]; $a[] = $b; unset($b); unset($a); 参照カウントの利点 未使用オブジェクトが即座に解放される 解放にかかるコストが全体に分散する 参照カウントの欠点 参照の追加にコストがかかる マルチスレッド環境に向かない 循環参照を扱えない $a = new stdClass(); $b = new stdClass(); $a->x = $b; $b->x = $a; $a = new stdClass(); $b = new stdClass(); $a->x = $b; $b->x = $a; unset($b); unset($a); 参照カウントでは循環参照を解放できない マークアンドスイープ (mark & sweep) 循環参照の解放のみ担う 最も基本的なマークアンドスイープ PHP のマークアンドスイープ マークフェーズ スイープフェーズ マーク 確実に使われているオブジェクト (ルート) に印を付ける そこから辿れるオブジェクトに印を付ける スイープ 全オブジェクトを調べて、印が付いていなければ解放する 図 PHP のマークアンドスイープ ほとんどのオブジェクトは参照カウントで解放される 全オブジェクトを走査しなくていい 循環参照「かもしれない」オブジェクトを登録 refcount を減らしたときに 0 にならなかった マーク 循環参照かもしれないオブジェクトを root buffer へ登録 root buffer から辿れるオブジェクトの refcount を 1減らす スイープ すべての root buffer から辿れるオブジェクトについて、 refcount = 0 なら解放する refcount > 0 なら refcount を1増やして root buffer から消す 図 PHP のマークアンドスイープ GC が呼ばれるタイミング root buffer が一杯になったとき (デフォルトで 10,000) PHP の GC 参照カウント + マークアンドスイープ 循環参照以外は参照カウントで、 循環参照はマークアンドスイープで解放 多くのオブジェクトは未使用になると即座に解放される 循環参照を形成しているオブジェクトは遅れて解放される fclose() は明示的に呼ぶべきか? 常に呼ぶべき 呼ばなくても問題ないかを判定するのが困難 呼ばなくても問題ない状態を維持できるとは限らない 話せなかったこと 複数スレッド/プロセス間での共有 リクエスト毎に確保・解放されるメモリとグローバルなメモリ Copy on Write 弱参照 memory_limit