-PR-
締切済み

Perl実行時のメモリ不足について

  • すぐに回答を!
  • 質問No.76984
  • 閲覧数1520
  • ありがとう数5
  • 気になる数0
  • 回答数3
  • コメント数0

お礼率 25% (1/4)

こんばんは。いきなりですが、質問があります。

CGIで動的にHTMLを作成したのですが
あるページに多数ユーザが接続しようとすると
フリーズしてしまいます。
調査してみたところ、Perlが実行時にメモリを
多く確保しているためのようです。
また、そのページではフレームを使用しているため、
1ユーザに複数プロセスが起動されるので、
それもメモリ不足の原因ではと思っています。

メモリの使用量を下げようとしているのですが、
知識足らずなため、思うようにいきません。

どなたか良い方法をご存知でしたら、
教えていただきたいのですが。

よろしくお願いします。
通報する
  • 回答数3
  • 気になる
    質問をブックマークします。
    マイページでまとめて確認できます。

回答 (全3件)

  • 回答No.2
レベル10

ベストアンサー率 64% (73/113)

いくつかチェックポイントはあると思います。
まず、そのCGIは本当に必要か。普段は静的なHTMLページを表示して、
情報が更新されたときだけそのHTMLページを更新するようなことです。
掲示板でも最近多いですよね。ただ見るときだけのときは「~xxx.cgi」
ではなくて「~/xxx.html」を閲覧するようなもの。それで済むなら
そうしましょう。

次に、やはりプログラムのシェイプアップでしょうか。これには、さまざま
な場合があるのでひとくちにご説明するのは無理ですが、よく見かける
ものを念頭にちょっとだけポイントを書いてみます。

・ファイルの中身を @data = <FILE> といった調子で丸ごと読みこんで
いる個所があったら、
while (<FILE>) {
}
の形に直しましょう。確保されるメモリが1行分で済むようになります。

・グローバル変数を多く使ってるならなるべく局所変数にしましょう。
$abcがforループの中でしか参照されないのだったら、
my $abc;
for $abc (@array) {
$abc = ....
}
よりも
for $abc (@array) {
my $abc = ....
}
のほうが、いいということです。ループを抜けるときに掃除されますから。
サブルーチンでも同様です。サブルーチンの中だけ使うのならそこで
my。

・サブルーチンを呼び出すとき、配列やハッシュを引数として受け渡しする
かわりにリファレンスを渡す。
&my_function(@bigbigbig_data);
....
sub my_function {
my (@bigbigbig_data) = @_;
for my $data (@bigbigbig_data) {
.....
}
よりも、
&my_function(\@bigbigbig_data);
....
sub my_function {
my ($bigbigbig_data_ref) = @_;
for my $data (@$bigbigbig_data) {
.....
}
の方がベターということです。Perlのサブルーチン呼び出しはコピーに
なります。上記の例であれば@bigbigbig_dataが丸ごとコピーされることに
なります。ここでリファレンスを渡すようにすると、リファレンスそのもの
だけがコピーされ、両方とも同じものを指す、すなわち余分なメモリを食わなく
なるわけです。まあこれは程度問題で、$abc = 123とかの小さいデータを
渡すときにもムキになってリファレンスにする必要はありませんが。

他にも、細かいテクニックはいろいろあります。(ラクダ本の後ろの
ほうにあるメモリを節約するテクニックについて解説した章も参考に
してください)

以上をやってもキツい場合、ちょっと細かいテクニックになりますが、
セマフォを使って制限できる場合もありますね。
乱暴に言えば、flockを一度に単数のアクセスに制限するものとするなら
一度に複数のアクセスを許すロックみたいなものです。
詳しくはperldoc -f semctlやperldoc IPC::Semaphoreをご覧ください。
OSによっては使えない場合もあります。

まあ、自前でロックファイルを作るような形で、セマフォにあたるものを
作成する方法もできなくはないでしょう。
20個なら20個のアクセスまでを許し、それを越えていたら20以下になるまで
スリープする、あるいはエラーページを吐いて終わるような仕掛けを。

あと、大胆に、CGIのいくつかを他のサーバにおいてそっちで起動するように
する方法もあるでしょう。

------
たしかにサーバ側でコネクションを絞る手もありますね。例えば
ApacheだとMaxClientsやMaxSpareServersで設定することになるんでしょうか。
でも1.3ぐらいだと、全体でのDirectoryごとに細かくコネクション数を
設定できなかったような記憶があります。CGI以外の静的ページについても
制限することになりますね。まあ、背に腹は代えられないってことですかね。
それとも最近のバージョンだと違うのかな?また別のサーバなら話はまったく
異なるでしょうね。


  • 回答No.1
レベル10

ベストアンサー率 18% (35/185)

一般的にはwebサーバがわでマックスのコネクション数を設定できるので
それで制御しましょう。
もしwebサーバをいじれないのなら、perlプロセスの数をpsコマンドで数えて
多かったら「不可が高いです」だけだして即終了してしばらくまってもらうとか
そうすれば最悪の事態は確率的に回避できます。

でも、一番懸命なのはスクリプトをもう一度みなおして無駄に変数を
つかってないか確認してみましょう。
  • 回答No.3
レベル10

ベストアンサー率 64% (73/113)

あ、今見返していたらバグが。すみません。
sub my_function {
my ($bigbigbig_data_ref) = @_;
for my $data (@$bigbigbig_data) {

for my $data (@$bigbigbig_data_ref) {
ですね。
なんか読み返すと、tayahaさんを初心者と決めつけてるようなところ
があって…お気を悪くしたらごめんなさい。

もしご存知無かったら、ということなのですが…そうそう、
サブルーチンの返り値となる変数もmyして結構ですよ。
sub my_func {
my $abc;
....
return $abc;
}
my_funcを呼び出した側で$abcを使ってる場合はmy_funcを抜けても
$abcは掃除されることはありません。(my_funcを呼び出した関数が
終わったときに掃除されます)
要するに、基本的になんでもmyを付けましょう、ということです。
perl -w オプションとuse strict;を使いましょう。
グローバル変数についても
use vars qw(@MY_GLOBAL_ARRAY);
として、明示的にグローバルとして使う!と宣言してないものがあれば
警告してくれます。
このQ&Aで解決しましたか?
AIエージェント「あい」

こんにちは。AIエージェントの「あい」です。
あなたの悩みに、OKWAVE 3,500万件のQ&Aを分析して最適な回答をご提案します。

関連するQ&A
-PR-
-PR-
こんな書き方もあるよ!この情報は知ってる?あなたの知識を教えて!
このQ&Aにはまだコメントがありません。
あなたの思ったこと、知っていることをここにコメントしてみましょう。

その他の関連するQ&A、テーマをキーワードで探す

キーワードでQ&A、テーマを検索する
-PR-
-PR-
-PR-

特集


専門家があなたの悩みに回答!

-PR-

ピックアップ

-PR-
ページ先頭へ