序文
PHP で開発をしていると一度はこんなメッセージを見たことがあるかと思います。
Fatal error : Allowed memory size of xxx bytes exhausted ...
上記エラーは許容されているメモリサイズを超えてしまった場合に発生するものです。
このエラーの対処法を調べると、主に以下のような方法がヒットすると思います。
- 許容メモリ量を増やす( memory_limit を変更する)
- php.ini で設定を変更する
- .htaccess で設定を変更する
- ini_set() で一時的に設定を変更する
- コードをチューニングする(不要なメモリ使用を減らす)
- unset() で明示的に変数を解放する
- gc_collect_cycles でGCを強制実行する
- 大容量の配列操作時は Generator を使う
- メモリ使用量を監視して許容メモリサイズを超えないように制御する
メモリ使用量を監視して許容メモリサイズを超えないように制御する 方法で対処しようとした際に memory_get_usage を使ってメモリ使用量を監視しようと試みたのですが、このメソッドの引数 $real_usage
に true/false
どちらを指定すべきなのかがいまいち分からなかったため調べてみました。
本題
$real_usage とは?
公式のマニュアルには以下のように記載されています。
real_usage
これを true に設定すると、システムが割り当てた実際のメモリの大きさ (未使用のページも含むもの) を取得します。 省略したり false を設定したりすると、使用したメモリのみを報告します。注意:
PHP は、emalloc() が割り当てたメモリ以外のメモリは追跡しません。
なるほど。よく分かりません。
ググってみたところ Stack Overflow で参考になりそうなものをいくつか見つけました。
特に この回答 が参考になりました。
PHP のメモリマネージャー(Zend エンジン)は、メモリが必要になる度に malloc()
を使用するわけではなく、大きなブロック(環境変数 ZEND_MM_SEG_SIZE
で設定されている単位でデフォルトは 256KB)でメモリを確保しておき、それを内部で管理しているそうです。
したがって、メモリ使用量には以下の2種類があるそうです。
- メモリマネージャーが確保したメモリ量( real usage )
=>$real_usage = true
- アプリケーションが実際に使用したメモリ量( internal usage )
=>$real_usage = false
上記を見て、$real_usage
という引数名とその説明文がやっと理解できました。
$real_usage = true or false ?
引数の用途が理解できたところで、当初の目的だった メモリ使用量を監視して許容メモリサイズを超えないように制御する には true/false
どちらを指定すべきなのかという話なのですが、「許容メモリサイズ(memory_limit)」の設定値は「1. メモリマネージャーが確保したメモリ量」の方を制限するものなので、この場合は memory_get_usage(true)
で監視するのが適していると思います。
特定のロジックにおけるメモリ使用量を測定したりする場合には memory_get_usage(false)
を使うのが良いのかなと思いました。
おまけ
環境変数 USE_ZEND_ALLOC=0
を設定すると「メモリマネージャーが大きなブロックでメモリを確保する」メカニズムが無効になり、メモリが必要になる度に malloc()
を使用する動きになるそうです。
パフォーマンスは大幅に落ちるようですが、外部のメモリトラッキングツールを使用する場合等にはこの設定が必要になりそうでした。