Slide 1

Slide 1 text

PHPの ガベージコレクション を深掘りしよう PHPer Kaigi 2025 Day 2 LT Rinchoku

Slide 2

Slide 2 text

アジェンダ ● ガベージコレクションとは ● PHPのガベージコレクションについて ● まとめ

Slide 3

Slide 3 text

最初に PHPで開発をしていてメモリ関連で下記経験したことあります か?

Slide 4

Slide 4 text

最初に PHPで開発をしていてメモリ関連で下記経験したことあります か? ● PHP Fatal error: Allowed memory size of ******bytes exhausted (tried to allocate XXXXbytes) ○ memory_get_usage(true)でメモリ使用量を見たり

Slide 5

Slide 5 text

最初に PHPで開発をしていてメモリ関連で下記経験したことあります か? ● PHP Fatal error: Allowed memory size of ******bytes exhausted (tried to allocate XXXXbytes) ○ memory_get_usage(true)でメモリ使用量を見たり ● 古いPHPバージョン環境で謎のunset

Slide 6

Slide 6 text

最初に なぜPHPerがメモリの管理・解放を気にしなくていいのか

Slide 7

Slide 7 text

最初に なぜPHPerがメモリの管理・解放を気にしなくていいのか 「PHPは勝手にメモリ管理してくれるよ」という 教えされた人もいるかも?

Slide 8

Slide 8 text

最初に なぜPHPerがメモリの管理・解放を気にしなくていいのか ガベージコレクションが実装されてるから

Slide 9

Slide 9 text

最初に ただ、 ガベージコレクション聞いたことあっても よく知らない

Slide 10

Slide 10 text

最初に たとえば、 ● どういうロジックで メモリを開放しているのか ○ 未使用ってどうやって決めているの? ● どのタイミング で呼び出されるのか

Slide 11

Slide 11 text

ガベージコレクションとは ● 動的に確保したメモリ領域から、不要となったメモリ領域を 解放し空き領域として再利用できる ための機能 ○ よく掃除のおばちゃんに例えられる ● メモリの再配置は行わない ● C/C++、Rustはガベージコレクションがない ● 主に下記手法が存在する ○ reference counting(参照カウント) ○ mark-and-sweep

Slide 12

Slide 12 text

PHPのガベージコレクションについて ● PHP5.3(2009年6月30日)から追加された機能 ○ 循環参照のバグなどはあったものの ● PHPはReference Counting(参照カウント )を採用 ○ 深さ優先探索を利用 ○ Concurrent Cycle Collection in Reference Counted Systemsを 採用 ● ガベージコレクションのロジックは下記に記載 ○ php-src/Zend/zend_gc.c ○ php-src/Zend/zend_gc.h ● 参照カウントやフラグの管理は php-src/Zend/zend_types.h

Slide 13

Slide 13 text

Reference Countingとは ● PHPの変数(zval)は下記4つの情報を持つ ○ 型 ○ 値 ○ is_ref ■ 「参照集合」の一部かどうかを示すブール値 ○ refcount ■ 1つの zval コンテナをどれだけ多くの 変数名が指すか ■ 「変数名」を「シンボル」とも呼ばれる ● 各スコープ単位にシンボルテーブルが 1つ作られ、変数名はこの シンボルテーブルに保管される

Slide 14

Slide 14 text

実際に見てみる

Slide 15

Slide 15 text

実際に見てみる refcountじゃない?

Slide 16

Slide 16 text

インターン化 ● PHP5.4以降に追加された文字列のインターン化 ● 同一の文字列を参照する場合に値を共有するための機能

Slide 17

Slide 17 text

実際に見てみる

Slide 18

Slide 18 text

Reference Countingとは ● ガベージコレクションが動く条件 ○ refcountが減少した時 ■ refcountが0であれば解放 が可能 ■ refcountが減少した時はゴミ候補 入り ● 詳しくは「ガベージコレクション > 循環の収集」を参照 ○ root_bufferが保有する値が一定値を超える

Slide 19

Slide 19 text

Reference Countingとは ● 内部的に色でRoot Zvalの状態を管理 している ○ BLACK:ベース。使用中か解放可能かは不明 ○ GREY:探査をして、refcountを1減少させたもの ○ WHITE:探査をした結果、解放できる ○ PURPLE:GC対象のRoot Zval ■ 変更のたびに各zvalを確認するのを防ぐ目的 ● 他にもGREEN、RED、ORANGEがあるが、PHPでは利用していな い

Slide 20

Slide 20 text

Reference Countingとは

Slide 21

Slide 21 text

PHPのガベージコレクションの動き 1. Root ZvalからGrayにマークをつける ○ GrayではなかったzvalをStackしておく ○ refcountを-1する 2. Root Zvalを探査する ○ GrayのRoot Zvalに対して i. refcountが正→Blackに変更 ii. GrayのzvalをWhiteに変更 3. Whiteにマークされたものを収集し、解放 ○ 収集時、White-> Blackに変更

Slide 22

Slide 22 text

PHPのガベージコレクションの動き 1. Root ZvalからGrayにマークをつける ○ GrayではなかったzvalをStackしておく ○ refcountを-1する 2. Root Zvalを探査する ○ GrayのRoot Zvalに対して i. refcountが正→Blackに変更 ii. GrayのzvalをWhiteに変更 3. Whiteにマークされたものを収集し、解放 ○ 収集時、White-> Blackに変更

Slide 23

Slide 23 text

PHPのガベージコレクションの動き 1. Root ZvalからGrayにマークをつける ○ GrayではなかったzvalをStackしておく ○ refcountを-1する 2. Root Zvalを探査する ○ GrayのRoot Zvalに対して i. refcountが正→Blackに変更 ii. GrayのzvalをWhiteに変更 3. Whiteにマークされたものを収集し、解放 ○ 収集時、White-> Blackに変更 削除のシミュレーション 循環参照により、未使用変数を見つけ る布石

Slide 24

Slide 24 text

PHPのガベージコレクションの動き 1. Root ZvalからGrayにマークをつける ○ GrayではなかったzvalをStackしておく ○ refcountを-1する 2. Root Zvalを探査する ○ GrayのRoot Zvalに対して i. refcountが正→Blackに変更 ii. GrayのzvalをWhiteに変更 3. Whiteにマークされたものを収集し、解放 ○ 収集時、White-> Blackに変更 循環参照を考慮して無限ループを回避 変更前に削除対象として収集済み

Slide 25

Slide 25 text

PHPのガベージコレクションの動き どういう動きをするかは分かった

Slide 26

Slide 26 text

PHPのガベージコレクションの動き どのタイミングで呼び出されているのか?

Slide 27

Slide 27 text

ガベージコレクションが実行されるまで (RootBuffer) 1. zend_assign_to_variable 2. GC_DTOR_NO_REF 3. gc_check_possible_root 4. gc_possible_root 5. gc_possible_root_when_full 6. gc_collect_cycles

Slide 28

Slide 28 text

zend_assign_to_variable(zend_execute.h)

Slide 29

Slide 29 text

zend_assign_to_variable(zend_execute.h)

Slide 30

Slide 30 text

GC_DTOR_NO_REF(zend_types.h)

Slide 31

Slide 31 text

GC_DTOR_NO_REF(zend_types.h)

Slide 32

Slide 32 text

gc_check_possible_root(zend_gc.h)

Slide 33

Slide 33 text

gc_check_possible_root(zend_gc.h)

Slide 34

Slide 34 text

gc_possible_root(zend_gc.c)

Slide 35

Slide 35 text

gc_possible_root(zend_gc.c)

Slide 36

Slide 36 text

gc_possible_root_when_full(zend_gc.c)

Slide 37

Slide 37 text

gc_possible_root_when_full(zend_gc.c)

Slide 38

Slide 38 text

至る所でgc_collect_cycleは呼ばれている ● returnを行う ○ ZEND_RETURN_SPEC_CONST_HANDLER ○ ZEND_RETURN_SPEC_TMP_HANDLER ● 代入を行う ○ zend_assign_XXXX

Slide 39

Slide 39 text

まとめ ● PHPにはガベージコレクションが存在する ○ ガベージコレクションがメモリの解放を行っている ● PHPのガベージコレクションとして参照カウント を採用 ● ガベージコレクション関連のコードはPHPのソース上に色んな 所にある ● ガベージコレクションを調べるだけで、PHPの他の機能につい て軽く知れるので、皆さんもやってみよう

Slide 40

Slide 40 text

自己紹介 ● 氏名:Rinchoku (リンチョク) ● 所属:eForce株式会社(近々…) ● X:@stupid_owl ● コミュニティ ○ SRE NEXT 2025 コアスタッフ ○ SRE Kaigi 2025 コアスタッフ ● 趣味 ○ ハンドメイド ○ 宝石鑑賞

Slide 41

Slide 41 text

参考 ● https://github.com/php/php-src ● https://www.php.net/manual/ja/features.gc.php ● https://qiita.com/hinako_n/items/8a7b366a3fe09f43dce8 ● https://www.php.net/manual/ja/features.gc.performance-considerations.php ● https://qiita.com/genie-oh/items/e6dfc49fb9899f931271 ● https://fortee.jp/phpcon-2022/proposal/1addf51d-6f72-4c96-9337-034ec6c c0643 ● https://qiita.com/pseudo_foxkeh/items/a15e4a5fd6ba679d4841 ● https://ja.wikipedia.org/wiki/%E3%82%AC%E3%83%99%E3%83%BC%E3%8 2%B8%E3%82%B3%E3%83%AC%E3%82%AF%E3%82%B7%E3%83%A7%E3 %83%B3

Slide 42

Slide 42 text

ご清聴ありがとうございました