TOPでRES値を見ていると、httpdの子プロセスがHTTPリクエストを処理するたびにメモリ使用量がどんどん増大していってるようなのですが、これはPHPの仕様でしょうか?それともPHPスクリプトの書き方の問題でしょうか?
PHPスクリプトの書き方次第で回避・緩和できるのか、Apache/mod_phpの仕様なので回避できないのかを知りたいです。
ネットでよく見る解説は、MaxRequestsPerChildを小さめに設定しておけというものです。たしかにそうすれば子プロセス再起動によりメモリ初期化できるのはわかります。
しかしこの対処法は、「PCが固まったら再起動しろ」と言ってるようなもので、いまいち腑におちません。
メモリリークの原因をつきとめる方法はないものでしょうか?
■環境
CentOS 5/PHP5/Apache2.2
これはmod_php(prefork)の仕様です。
Apache/mod_php(prefork)の組み合わせでは、リクエストを処理する都度、複数の子プロセスを起動します。したがって、同時に処理するリクエストが多くなればなるほど、メモリを含む消費リソースが膨らみます。さらに、mod_php(prefork)では、リクエスト処理が終わるまでメモリを解放しません。
現在のリクエストに割り当てられているメモリ量はmemory_get_usage関数で調べることができます。
http://php.net/manual/ja/function.memory-get-usage.php
それは違うと思います。
そもそも、キャパシティを超えたアクセスを受け付ける設定にしていることが問題です。10人にしか乗れない吊り橋に30人を通そうとするのと同じ事で、お客さんの安全を第一に考えるなら、キャパシティを超えたお客さんには待ち行列に入ってもらうか、キャパシティの増強工事を行うべきです。
これはmod_php(prefork)に限ったことではなく、MaxRequestsPerChildやmemory_limitの値を見直すことは必要です。
回答ありがとうございます。
2013/03/14 08:53:44ですがちょっと誤解があるようです。
質問の書き方が悪かったのかもしれません。
>Apache/mod_php(prefork)の組み合わせでは、リクエストを処理する都度、複数の子プロセスを起動します。
「リクエストを処理する都度起動ではなくて、前もっていくつか起動して待ち受ける」ですよね。
>したがって、同時に処理するリクエストが多くなればなるほど、メモリを含む消費リソースが膨らみます。
はい、それは理解しています。
私が問題にしているのは、リクエストが増えるにつれてプロセス数が増えること(それは当然ですので)ではありません。
>さらに、mod_php(prefork)では、リクエスト処理が終わるまでメモリを解放しません。
私が観察したところ、リクエストが終了してもメモリを解放しないのです。
それが、mod_phpの仕様なのか私のPHPスクリプトの書き方が悪いのかどちらでしょう、というのが質問の趣旨です。
> 現在のリクエストに割り当てられているメモリ量はmemory_get_usage関数で調べることができます。
ありがとうございます。これはまだ試してなかったのでやってみます。
> キャパシティを超えたアクセスを受け付ける設定にしていることが問題
いえ、キャパシティを超えてるわけではありません。キャパシティにも余裕はあります。
私が問題にしてるのは吊り橋の数とお客さんの数ではなく、吊り橋1本の重さの話しです。
吊り橋10本でお客さんが1人しか通らなくても、お客さんが渡り終わった後に吊り橋1本の重さが増えたままなのはなぜかということです。
もうちょっと噛み砕いて言うと、私が観察したのは下記のような現象です。
2013/03/14 08:58:56* 吊り橋が1本あるとします。100Kだとします。
* 1人目のお客さんが、吊り橋に乗りました。150KGになりました。
* お客さんが吊り橋を渡り終えました。吊り橋の重さはなぜか150Kのままです。
* 2人目のお客さんが吊り橋にきました。吊り橋の重さが200Kになりました。
* 2人目のお客さんが渡り終えました。吊り橋の重さはなぜか200Kのままです。
こうやって、お客さんがくるたびに吊り橋がどんどん重くなってしまうのです。
お客さんの数がMaxRequestsPerChildに達すると、吊り橋が破壊・再作成されてまた100Kに戻ります。
質問は、お客さんがわたり終わった後に吊り橋の重さが100Kに戻らないのはなぜか?です。