Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PHP で PHP のメモリプロファイラをつくろう

sji
October 08, 2023

PHP で PHP のメモリプロファイラをつくろう

PHP カンファレンス 2023
10:50 〜
Track2

sji

October 08, 2023
Tweet

More Decks by sji

Other Decks in Programming

Transcript

  1. PHP
    で PHP
    のメモリプロファイラを作ろう
    五十嵐 進士 / sji / sj-i / @sji_ch
     

    View Slide

  2. 自己紹介
    @sji_ch
    SNS
    上のアイコンは GitHub
    が自動生成した奴

    View Slide

  3. 生まれも育ちも仙台

    View Slide

  4. PHP
    カンファレンス仙台とかやった

    View Slide

  5. ふつうのサラリーマン


    株式会社インフィニットループ仙台支社所属
    スマホゲーのサーバサイドプログラマ
    地元が仙台や札幌の人とかはぜひ一緒に働きま
    しょう

    View Slide

  6. Agenda
    メモリとはなんぞや(約 10
    分)
    PHP
    のメモリ管理機構について(約 10
    分)
    PHP
    のメモリ消費量の計測方法(約 10
    分)
    PHP
    のメモリプロファイラを自作する取り組み(約 15
    分)

    View Slide

  7. メモリの概要

    View Slide

  8. メモリはコンピュータの部品
    コンピュータは様々な部品から構成
    メモリはその中の一つ

    View Slide

  9. コンピュータは数値で動く
    2
    つの状態を持つものの並び =
    信号 =
    数値
    電気の強弱
    磁性体の向き
    0
    と 1
    この信号パターンならこう動く、というのが機械への命令
    命令を動作の種類と内容を分けて構成すれば様々な情報が数値に

    View Slide

  10. CPU
    は鳥頭
    CPU
    が命令を処理
    CPU
    自体では多くの命令を覚えられない
    CPU
    が命令を読み取るための装置が必要

    View Slide

  11. メモリが数値の並び(=
    情報)を大量に記憶
    メモリが CPU
    のために情報を記憶
    CPU
    はメモリから情報を読んでメモリに情報を書き込む

    View Slide

  12. 扱うデータの単位
    1
    ビット 0
    か 1
    のどちらかの値を持つ単位
    1
    バイト 8
    ビットの並び

    2
    の 8
    乗で 0
    から 255
    までの 256
    種類の値を持つ
    1
    キロバイト 1,000
    バイト or 1,024
    バイト
    1
    メガバイト 1,000
    キロバイト or 1,024
    キロバイト
    1
    ギガバイト 1,000
    メガバイト or 1,024
    メガバイト

    View Slide

  13. メモリはバイト単位のデータの並び
    メモリはバイトの情報をおさめた箱の並び
    一つ一つの箱に背番号 =
    アドレス、番地
    ある番地や番地の範囲をメモリ領域と呼ぶ

    View Slide

  14. メモリは限られた資源
    メモリは CPU
    に大量に読み書きされる
    メモリが遅いほど CPU
    が待たされることに
    メモリは比較的高速に動作するが、高価で大容量化が大変
    ついでに通電しなくなると記録していた情報が消える
    ストレージと組み合わせてやりくり
    遅くても安く大容量化でき、通電しなくても情報が消えない

    View Slide

  15. メモリは OS
    が管理
    コンピュータ上では複数プログラムが同時に動く
    マルチプロセス
    OS
    がプロセス間でハードウェア資源の利用を仲介
    メモリも OS
    が管理
    プロセスは OS
    にメモリを要求
    OS
    はプロセス間を仮想メモリ空間で隔離しながらメモリを割り当て
    プロセスは自分だけのメモリ領域を使っているように見える
    ストレージとも組み合わせてやりくり(スワップ)

    View Slide

  16. それでも無い袖は振れない
    ストレージはメモリと比べて圧倒的に遅い
    スワップが発生すると CPU
    が全然パワーを発揮できない
    設定でスワップを切ったり制限した状態で動かすこともよくある
    メモリが本当に足りなくなると OOM Killer
    にプロセスを殺されたりする
    各プログラムでなるべく無断のないメモリの使い方が必要

    View Slide

  17. PHP
    のメモリ管理機構:

    memory_limit
    あたり

    View Slide

  18. Allowed memory size of 134217728 bytes exhausted
    (tried to allocate 4096 bytes)

    View Slide

  19. memory_limit
    とは
    リクエストごとのメモリ上限を指定する ini
    項目
    安全装置
    PHP
    はマルチプロセスでリクエストを処理
    マシンリソースを食いつぶさないよう制限できる
    リクエストの処理が memory_limit
    を越えたらプロセスが自刃する
    最近のデフォルト値は 128MB
    プロジェクトや利用箇所によって違う設定にしてるはず

    View Slide

  20. ZendMemoryManager
    PHP
    処理系のメモリ管理部品
    2
    種類のメモリ領域
    リクエストごとのメモリ領域
    処理系や C
    拡張は libc
    の malloc
    や free


    パクった emalloc
    や efree
    などの API
    で操作
    永続メモリ領域
    通常 libc
    の malloc
    とか free
    が使われる
    どちらも最終的には OS
    からもらう

    仮想メモリ領域を使う
    名前のZend
    はZeev
    とAndi
    の名前から

    View Slide

  21. 基本はリクエストごとのメモリ領域に入る
    PHP
    スクリプトのメモリ状態は通常リクエストごとにリセット
    大部分のデータをリクエストごとのメモリ領域で管理
    リークの心配があまりなくなる
    memory_limit
    での制限対象はこっちのメモリ領域
    memory_get_usage()
    などでとる情報もこの部分

    View Slide

  22. memory_limit
    の制限の対象外
    永続メモリ領域や Zend Memory Manager
    管理外の領域 は memory_limit
    の対象外
    たとえば Xdebug
    が動作に使うメモリ
    phpdbg
    だと Zend Memory Manager
    経由で似た情報を持ったり
    どちらでカバレッジをとるかで PHPUnit
    でのメモリ使用量報告が大きく変わる
    opcache
    が SHM
    として共有メモリ上に管理するのも別
    今回のトークではこの辺の話はしない

    View Slide

  23. PHP
    のメモリ管理機構:

    リクエスト内でのメモリの確保と解放

    View Slide

  24. メモリの確保は使うときに処理系がこっそり
    スクリプト内で「メモリ領域を確保」のような関数は(基本的に)ない
    PHP
    スクリプトでメモリが必要になったら裏で処理系が ZMM
    で確保
    変数を使うとか
    配列の要素を追加するとか
    オブジェクトを new
    するとか
    スクリプト内のどの部分がどのくらいメモリを必要とするかは意識せず使える
    逆に言うとふつうには意識することができない
    memory_get_usage()
    を至るところに差し込めば近づけはする

    View Slide

  25. リクエスト内で不要になったメモリ領域は?
    単純な値を持つローカル変数は VM
    スタックで管理
    整数値や浮動小数点数、bool
    値など
    関数が終了し次第そのまま破棄してよい
    オブジェクトや配列、文字列などは参照カウントで順次解放
    スクリプト内で使われなくなった領域から解放される
    循環参照は参照カウントでは破棄できない
    M&S
    っぽく可能性ある奴を一通りなめる循環参照 GC
    がある
    https://www.php.net/manual/ja/features.gc.collecting-cycles.php

    View Slide

  26. 前提: zval
    について
    PHP
    の値は zval
    という 128bit (= 16byte)
    の構造体で表現
    zval
    は値の種類を表す型情報と、値そのものを持つ
    値そのものは union
    で表現される 64bit
    (= 8byte
    )分
    long, double, true, false, string, array, object, null
    などなんでも入る
    string
    、array
    、object
    、resource
    の zval
    は詳細データ構造へのポインタが値
    処理系で内部的に使う一部の特別な値でも利用
    クラスの定義情報を名前から引くための辞書など

    View Slide

  27. VM
    スタック
    ローカル変数領域は VM
    スタック内の zval
    配列
    関数呼び出しのたびに VM
    スタックへ必要なロ
    ーカル変数や引数用の領域を確保
    関数が return
    するたびにローカル変数の zval

    含むコールフレーム領域を取り除く
    整数値や浮動小数点数、bool
    値のような単純な
    値はこれで十分
    zval
    が詳細データへのポインタを持つ系なら?
    オブジェクトや配列、文字列など
    実体は別の領域、zval
    削除だけではダメ
    function f1() {$a = 123; f2();}

    function f2() {$b = 456; $c = 789; f3();}

    function f3() {$e = 'abc'; /*
    今ここを実行中とする
    *

    View Slide

  28. 参照カウント
    オブジェクトや配列、文字列などの実体は参照カウントを持つ
    今 N
    箇所で使われています、の N
    関数へ渡したり関数から返したり異なる変数へ代入したりするたび 1
    増える
    参照が消えるたび 1
    減る
    ローカル変数が unset()
    されたり
    スコープを抜けてスタックから破棄されたり
    カウント 0
    になったら解放

    View Slide

  29. 循環参照 GC
    配列とオブジェクトでは循環参照が発生し得る
    参照カウントでは循環参照を解放できない
    参照カウントを減らした際 0
    にならない配列やオブジェクトがあれば容疑者入り
    処理系は疑わしいものを root buffer
    と呼ばれるバッファへすべて記録
    参照カウントが 0
    になるなどして破棄される際は root buffer
    から除去
    root buffer
    がある程度たまって閾値を超えると循環参照 GC
    を実行
    細かい話は y-uti
    先生の『PHP
    の GC
    の話』を見よう
    https://www.slideshare.net/y-uti/php-gc

    View Slide

  30. 循環参照 GC
    の利用上の注意点
    循環参照 GC
    のトリガは root buffer
    の埋まり具合
    埋まり具合が閾値を超えないと循環参照 GC
    は実行されない
    つまり memory_limit
    を超えても循環参照 GC
    は実行されない
    手動で良いタイミングに gc_collect_cycle()
    を呼ぶだけで

    memory_limit
    越えを避けられる場合も

    View Slide

  31. リクエスト終了まで解放されない領域
    リクエスト終了まで解放されない領域もある
    グローバル変数
    関数内静的変数
    クラス static
    ・クラス定数
    定数
    コンパイルされたファイルや関数・クラスの情報
    コンパイラが使うための作業用領域

    View Slide

  32. 不意にスクリプトが終了した場合の処理
    リクエストの処理中に不意にスクリプトが終了した場合は?
    exit()
    とか
    リクエストごとのメモリ領域そのものが解放されるので基本は大丈夫
    オブジェクトがデストラクタで永続領域の何かを解放したがっているかも
    EG(objects_store)
    に全オブジェクトの参照があり、シャットダウン処理で順次破棄
    PHP
    マニュアルのデストラクタのページにも少し書いてある
    https://www.php.net/manual/ja/language.oop5.decon.php#language.oop5.decon.destructor
    あるいは、スクリプトの終了時にも順不同でコールされます

    View Slide

  33. 何がリクエストの中でメモリを使っているか、

    駆け足でまとめる
    スクリプトコンパイル時の作業用領域
    コンパイルされた VM
    命令列
    グローバル変数用の zval
    領域
    文字列、配列、オブジェクトの実体
    定数用の zval
    領域
    クラスや関数の静的領域
    VM
    スタック
    処理系内の各種管理データ
    定数や関数・クラスの各種定義情報とか
    EG(objects_store
    ) とか
    などなど

    View Slide

  34. PHP
    のメモリ使用量の計測事情

    View Slide

  35. 計測の必要性:
    メモリ使用量はサーバ性能につながり得る
    Web
    システムの多くは I/O
    バウンドなので CPU
    が遊びがち
    サーバ資源を有効活用するのに PHP
    ワーカを増やしたい
    CPU
    が余っていても各ワーカプロセスがメモリを食いすぎると並列度を上げづらい
    実質的に可処分メモリ /
    ワーカの消費メモリが並列度の限界になる

    View Slide

  36. 計測の必要性: PHP
    ツールはメモリを食いがち
    Web
    以外のシーンでも最近の PHP
    は汎用言語としてわりと使える
    GB
    単位でメモリを食う静的解析ツールの改善などに糸口が見つけられると嬉しい

    View Slide

  37. 計測の必要性: long running
    への安心感
    リクエストごとに状態をリセットしない AltFPM
    が成熟してきた
    roadrunner / swoole
    など
    PHP
    ワーカがリクエストをまたいで状態を保持し続ける利用シーンも今後増えていくかも
    何がどこでメモリを使っているか分からないのは可観測性に問題

    View Slide

  38. 計測の必要性:
    当てずっぽうでは当たらない
    誰が言ったか「推測するな、計測せよ」
    処理時間の場合と同様、メモリ使用量もボトル
    ネックが生まれがち
    ごく一部の原因が多くのメモリを消費する
    ある程度以上の規模のシステムで改善点を突き
    止めるのは当てずっぽうでは難しい
    砂漠でゴマ粒を、haystack
    で needle
    を探すよ
    うなもの

    View Slide

  39. 計測の必要性はあるが既存の方法は限られている
    memory_get_usage() / memory_get_peak_usage()
    xdebug / tideways_xhprof
    php-memprof
    php-meminfo

    View Slide

  40. memory_get_usage() /

    memory_get_peak_usage()
    memory_get_usage()
    で現在のメモリ使用量取

    memory_get_peak_usage()
    でリクエスト内での
    最大使用量取得
    PHP 8.2
    以降は memory_reset_peak_usage()

    最大使用量記録をリセットできる
    ある処理を行う前後での差分を取ることで、
    その処理でのメモリ増加量や減少量を計測で
    きる
    しかし……
    $before = memory_get_usage();

    $result =
    なにかの処理
    ();

    $diff = memory_get_usage() - $befo

    View Slide

  41. memory_get_usage() /

    memory_get_peak_usage()
    の問題点1
    問題になるケースは何らかの理由でメモリが解放されていない
    いつ確保されたメモリがいつ解放されているか
    何が解放されるべき時に解放されていないのか
    使用量の集計だけでは分からない
    ごく一部のケースにアテがつけられるだけ
    ある処理で一気に確保されたメモリが、その後の処理で解放されている場合もある
    どこで参照カウントが 0
    になるかは簡単には分からない場合が多い
    適切に解放されていれば別に何も問題がなかったりする

    View Slide

  42. memory_get_usage() /

    memory_get_peak_usage()
    の問題点2
    そもそも仕込むのが面倒くさい
    面倒くさい上に問題点 1
    のためにリターンが大したことない
    計測対象のソースコードへ大きな改変が必要な手段は選びづらい

    View Slide

  43. xdebug / xhprof
    処理時間を計測するプロファイラ機能を持つ
    おまけ機能で関数の出入りの際にメモリ使用量・ピーク使用量を自動で記録できる
    PECL
    の xhprof
    は最近メンテナが変わって復活
    tideways_xhprof
    は役割を終えたとして今月(10/6
    )アーカイブされた
    本質的には memory_get_usage() / memory_get_peak_usage()
    方式と同じ
    減らない理由が分からない、何が減っていないのかが分からない
    https://xdebug.org/
    https://github.com/longxinH/xhprof

    View Slide

  44. php-memprof
    現状での良い選択肢の一つ
    PCEL
    の C
    拡張
    スクリプトの全関数実行をフックして今どこを
    実行しているか、を追跡
    zend_mm_set_custom_handlers()
    で ZendMM

    メモリ確保・解放処理をフック
    emalloc()
    や efree()
    の実装を差し替え
    どこで確保されたメモリがどこで解放された
    か、解放されていないのはどこか、を関数実
    行単位で追跡可能
    memory_limit
    超過時に自動出力する機能も
    https://github.com/arnaud-lb/php-memory-
    profiler

    View Slide

  45. php-memprof
    の弱点
    全関数実行と全メモリ確保・解放処理のフックにはオーバーヘッドがある
    計測用に本来とは異なる処理が行われ、厳密には挙動が変わる
    本番環境での問題特定には不向き
    「どの関数の」確保が解放されていないか、までは分かるが、何の領域かまでは不明
    処理系への C
    拡張のインストールが必要

    View Slide

  46. php-meminfo
    PECL
    にはないが C
    拡張
    meminfo_dump() を提供
    呼び出し時点のスクリプト内のコールスタッ
    クの変数情報を JSON
    としてダンプする
    ダンプ内容は PHP
    スクリプトで解析・集計可能
    「何が」メモリ食いかをかなり絞り込める
    https://github.com/BitOne/php-meminfo

    View Slide

  47. php-meminfo
    の弱点
    2022
    年 3
    月の CI
    設定の修正を最後に更新されていない
    循環参照には対応していない
    定数や関数の静的変数には対応していない
    処理系への C
    拡張のインストールが必要
    スクリプト側を修正してのダンプ出力が必要

    View Slide

  48. PHP
    で PHP
    のメモリプロファイラを作ろう

    View Slide

  49. 前提:
    旧作・reli

    PHP
    の PHP
    による PHP
    のためのプロファイラ
    前から PHP
    スクリプトの処理時間を計測するプロファイラ reli
    を PHP
    で作ってる
    処理系の ELF
    バイナリと procfs
    のメモリマップを解析
    外部プロセスの処理系の重要構造体の仮想アドレスを特定
    FFI
    でシステムコールを呼び別プロセスの処理系内のメモリを読む
    gdb
    などのデバッガと同じようなことをやる
    処理系内部のメモリレイアウトの知識を持って内部情報を解釈
    実行中の関数・VM
    命令のコールトレースをサンプリングで取得
    よく取れるものがボトルネック
    https://github.com/reliforp/reli-prof

    View Slide

  50. 処理時間以外の情報も取れるのでは?
    元ネタの phpspy
    ではその時点のメモリ使用量・最大使用量を取得できる
    これは結局 php-memprof
    以外と同じ問題を持つ
    元ネタの phpspy
    は指定したファイル・行の

    ローカル・グローバル変数の値の監視などもできる
    似たことをもっと大規模にやったら?

    View Slide

  51. EG
    から読めば読めそうな情報
    グローバル変数全部入りテーブル
    定義済み関数全部入りテーブル
    定義済みクラス全部入りテーブル
    定義済み定数全部入りテーブル
    コールスタック内ローカル変数
    わりと全部取れるのでは?

    View Slide

  52. チャレンジ:
    稼働中システムへの利用可能性
    データの取得中はさすがに対象プログラムを停止させたい
    実行中の VM
    状態変化の影響は単なるコールトレース以上の筈、読む箇所も多い
    止めなければ対象の状態を取得している間に状態が変わってしまう
    FFI
    経由で ptrace
    を呼べば止められる
    しかし長く止めてしまうと本番環境などで使い辛くなる
    解析処理には時間がかかる

    View Slide

  53. 想定する解法:
    メモリプールのまるごとコピー
    処理系のメモリプールをほぼ解析なしで一気にコピーして即座に停止解除
    リクエストごとのプールと永続領域と両方
    コピー後のデータでじっくり解析
    力こそパワー

    View Slide

  54. プロセス外からのコピー速度
    いまどきの DDR4
    や DDR5
    の速度ならわりといける?
    process_vm_readv
    で別プロセスから 1GB
    分のメモリをコピってくるのに家のマシンで 234
    ミリ秒
    システムコールの処理としてのオーバーヘッドがまあまあある
    素朴な memcpy
    などとは雲泥
    とはいえよくある memory_limit
    はこの 1/4
    や 1/8
    以下
    遅いことは遅いが許容できないほどでもない
    本当に困ったら対象へ C
    拡張でも突っ込めば memcpy
    の速度で共有メモリ域へコピー可能

    View Slide

  55. チャレンジ:
    メモリプールの見つけ方問題
    外部プロセスのメモリプールのアドレスは自明でない
    AG (Allocator Globals)
    は公開シンボルではないので普通にはたどれない
    デバッグシンボル付の処理系なら取れるが避けたい、使う側がめんどくさいから

    View Slide

  56. リクエストごとのメモリプールの構造
    ZendMM
    の管理メモリは 2MB
    ごとのチャンク
    各チャンク内部で更に 4KB
    ごとのページへ分割
    emalloc
    は各チャンクを更に小分けにしたり複数
    ページまとめたりした領域を返す
    各チャンク領域先頭は zend_mm_chunk
    構造体
    zend_mm_chunk
    は双方向リンクリストで各チャ
    ンクをつなげている
    最初に確保されるチャンクはメインチャンクと
    いう特別なチャンク
    プール全体の管理情報 zend_mm_heap
    を持つ
    処理系内アロケータからは AG(mm_heap)
    とし
    てデータ領域のポインタからアクセス

    View Slide

  57. 想定する解法:
    めちゃくちゃ強引な手で見つける
    一旦てきとうなリクエスト内確保の要素のメモ
    リアドレスを EG
    経由で解決
    /proc//maps
    を見て当該 mmap
    領域を特定
    2MB
    のチャンクサイズにアラインしたアドレ
    スを総当たりしつつ、メインチャンクに特有
    の構造を持つかで同定
    メインチャンクに固定オフセットにヒープ
    全体を管理する zend_mm_heap
    全チャンクは先頭要素にこれへのポインタ
    全チャンクが通し番号を持ち、メインは 0
    全チャンクは双方向リストで接続
    力こそパワー

    View Slide

  58. チャレンジ:
    循環参照 GC
    の対象取得
    循環参照 GC
    の root buffer
    は普通にはプロセス外から見えない
    デバッグシンボル付きの処理系を使えばいけるが避けたい
    root buffer
    が取れないと特定できない領域がある
    循環参照のために回収されていないどこからも参照されていない領域
    メインチャンクのようなズルができない

    View Slide

  59. 想定する解法:
    半分諦める
    root buffer
    が取れなくても EG(objects_store)
    に全オブジェクトの参照がある
    この中にある他から参照をたどれない奴らが循環参照 GC
    の対象かもしれない候補
    実際は拡張が持つ固有のデータ構造などが有効な参照を握っている可能性も
    とにかくオブジェクトの情報取得は漏れなく確実にできる
    循環参照を起こし得るのはオブジェクトと配列のみ
    オブジェクトをカバーできるだけでかなり有効な筈

    View Slide

  60. チャレンジ:
    どのタイミングで取得するか
    php-memprof
    ならスクリプト終了時にプロファイル結果を吐ける
    memory_limit
    越え時の自動出力も可能
    外部プロセスからのサンプリング方式ではプロセスを止めるタイミングを選びきれない
    止めた瞬間が対象プロセスにとってどういうタイミングかが分からない
    リクエストの開始直後でメモリ状態に何の問題もないタイミングかもしれない
    メモリ使用量が一旦膨れ上がった後ある程度回収されて平穏なタイミングかもしれない

    View Slide

  61. 想定する解法:
    色々できるようにしてみる
    memory_get_usage()
    相当の情報は zend_mm_heap.size
    経由で取れる
    サンプリングで閾値を越えた場合にメモリ領域のダンプを取得、といった対応もできる
    対象プロセスに手を入れる解法を許容し、自らメモリダンプの取得を依頼できるようにする手も

    View Slide

  62. チャレンジ:
    どのように結果を出力するか
    php-memprof
    なら実質的に関数実行の性能計測と同様の可視化が可能
    KCachegrind
    などで関数呼び出しのツリーを表示
    こちらもプロセス全体を根として各種情報をぶら下げたツリーとして扱うことは可能だが……
    複数の箇所から参照されるデータをどう扱えばよいか

    View Slide

  63. 想定する解法: PHPer
    なら SQL
    ではないか
    RDB
    のテーブルをいくつか定義し
    SQLite
    などに各種情報を突っ込む
    視点を変えて集計できると使い勝手よさそう
    クラスごとのメモリ使用量や参照元を絞った解析とか
    FUSE
    でファイルシステムとしてサイズ情報をマウント、とかも考えはした
    参照をハードリンク扱い
    du
    や nautilus
    などのファイル容量集計などで集計を見れるみたいな
    わりと真面目に検討したが、SQL
    の方が PHPer
    らしいかなと思い直した

    View Slide

  64. 実際にある程度作ってみた PoC
    について
    まだ見栄えのする出力がない
    ←のでしょうがなくJSON
    ダンプ

    (たぶん会場でよく見えない)
    https://github.com/reliforp/reli-prof/pull/294

    View Slide

  65. できている部分
    PHP 8.2
    ターゲット前提の対応
    zval
    のダンプ
    対象プロセスの各種データのダンプ
    グローバル変数テーブル
    定義済み関数テーブル
    定義済みクラステーブル
    定義済み定数テーブル
    コールスタック内ローカル変数
    デバッグシンボルなしでのメインチャンクの特定
    サイズ情報のある程度の集計

    View Slide

  66. まだの部分
    丸っとコピーしたメモリダンプからのゆっくり解析
    EG(objects_store)
    の対応
    取得タイミングのがんばり
    RDB
    への処理結果の突っ込み
    Fiber
    対応
    参照カウントの取得・循環参照の検知
    FFI
    など各拡張固有のデータ構造の対応
    複数バージョンの PHP
    対応
    ZTS
    対応

    View Slide

  67. うまいこといくと手に入りそうなツール
    対象プログラム無修正で使える
    プロセス外からスクリプト内のほぼ全ての状態を取得し SQL
    でクエリ可能とできる
    集計によりメモリリークやメモリボトルネックを特定できる
    ちょっとしたデバッガのかわりにも使える
    方向性は php-meminfo
    に近いが、PHP
    製で PHPer
    が修正可能

    View Slide

  68. まとめ

    View Slide

  69. メモリは限られた大事な資源

    View Slide

  70. PHP
    の実行時情報は基本リクエストごとのメモリ領域に

    View Slide

  71. php-memprof


    現在あるメモリ使用量計測の選択肢では有力

    View Slide

  72. 根性があれば PHP
    でも力業により

    メモリプロファイラは作れる(たぶん)

    View Slide

  73. おしまい

    View Slide