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

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

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

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

よろしくお願いします。

このQ&Aに関連する最新のQ&A

A 回答 (3件)

あ、今見返していたらバグが。

すみません。
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);
として、明示的にグローバルとして使う!と宣言してないものがあれば
警告してくれます。
    • good
    • 0

いくつかチェックポイントはあると思います。


まず、その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以外の静的ページについても
制限することになりますね。まあ、背に腹は代えられないってことですかね。
それとも最近のバージョンだと違うのかな?また別のサーバなら話はまったく
異なるでしょうね。
    • good
    • 0

一般的にはwebサーバがわでマックスのコネクション数を設定できるので


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

でも、一番懸命なのはスクリプトをもう一度みなおして無駄に変数を
つかってないか確認してみましょう。
    • good
    • 0

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

QPerlのプロセス

Windowsでホームページを公開しています。

ActiveState Perl5.8.7
Apache 2.0.54 (Win)

サービスでApacheを停止してもタスクマネージャーを見ると
perlのプロセスが4つほどあり、DocumentRootのフォルダを削除しようとしても
できません。通常Apacheの管理下なので、サービスを止めると、
ファイルの書き換えは出来ると思いますが、パールのprocessが残っているせいか
入れ替えができません。Windowsを再起動すれば良いかもしれませんが
ファイルの入れ替えごとに再起動は苦痛なので、PerlのプロセスをKILLできる方法が
知りたいです。TASKMGR.EXEで殺すことはできませんでした。

いつまでもperlのプロセスが残るので、何かソフトか対策はあるのでしょうか?

後、予断ですが Windowsでサーバー立てるのは危険でしょうか?

Aベストアンサー

perlのプロセスが残る理由は分かりませんが、
TASKMGR.EXEで殺すことのできないプロセスを、
リソースキットのKill.exeで殺せる場合があります。
以下のサイトにもあります。

MUST- HAVE UTILITIES
http://www.mattkruse.com/utilities/

Kill.exe and tlist.exe

参考URL:http://www.mattkruse.com/utilities/

Q動的な? 多次元ハッシュ

text---------------------
社会\t1
社会\t社会問題\t4
社会\t社会問題\t教育問題\t5
---------------------text

タブ区切りのテキストファイルを読み込んで
最後の値がハッシュ値になるような
深さがまちまちな多次元ハッシュをループで作りたいのです

手作業だと
$HASH{社会}=1
$HASH{社会}{社会問題}=4
$HASH{社会}{社会問題}{教育問題}=5

できるだけ動作を軽くしたいので、evalや$1での置き換え等は
使いたくないのです
どなたか教えてください

Aベストアンサー

>キー自体を使いたい(splitするコストがかかりますよね)
キー自体は、読み出す時にsplitするのだろうし、キーと値が切り出せれば別にsplitする必要もなく、'\t'を'/'にする必要もない(タブそのままでも良い)ですし、
ハッシュから値を読み出す時にも、キーが既に別々になっている状態で
$key1."/".$key2
のように連結すればいいだけのことで、
かえってテキストファイルによって動的に深さが決まるようなキーの場合、
%HASH{$key1}{$key2}…のような形で動的に深さを決定してアクセスするのが面倒です。

>いかんせん大量のデータ数&量を処理しようとしているので、なるべく軽くと思ってます
読み込みの部分が大量にあるとしても、それほど、重くなるとも思えません。
ハッシュからのアクセスの部分で言えば、かえって手順が簡単だと思います。

#3で指摘されているように、構造としてもうまく行かない場合があるようです。
#3でも言われているように、大量にデータがあるようなハッシュの場合、データの構造を変更して、DBに接続したハッシュにするのも1つの方法だと思います。

>キー自体を使いたい(splitするコストがかかりますよね)
キー自体は、読み出す時にsplitするのだろうし、キーと値が切り出せれば別にsplitする必要もなく、'\t'を'/'にする必要もない(タブそのままでも良い)ですし、
ハッシュから値を読み出す時にも、キーが既に別々になっている状態で
$key1."/".$key2
のように連結すればいいだけのことで、
かえってテキストファイルによって動的に深さが決まるようなキーの場合、
%HASH{$key1}{$key2}…のような形で動的に深さを決定してアクセスするのが面倒です。
...続きを読む

Qperlでゾンビプロセスが発生

お世話になります。

サーバーの変更後に、
それまで使っていたCGIでゾンビプロセスが発生するようになってしまいました。

以前のサーバーはFreeBSDでそのような事がなかったのですが、
新しいサーバーCentOS5になってから発生するようになってしまったのですが
どのような原因が考えらますでしょうか。

perlやSSIを使った時にだけ発生してしまいます。

色々しらべてはみたのですが、

mod_cgid.so

SSIではこれを無効にすればよいと言うのを見かけまして apache2のhttpd.confを見てみたのですが
LoadModule cgi_module modules/mod_cgi.so のみで
存在していませんでした。


同じプログラムでサーバー変更前はゾンビプロセスは全く発生しなかったのですが、
変更後に今まで大丈夫だったすべてのCGI(perl)プログラムで
ゾンビプロセスが発生するようになってしまいました。

ゾンビプロセス自体は、発生後に消える状態ではあります。


これだけの情報では予測もつかないと思いますが、
もし何かこれが原因では・・・と言うのがございましたらご教授いただけますと幸いです。


お手数をおかけしますが、何卒よろしくお願い致します。

お世話になります。

サーバーの変更後に、
それまで使っていたCGIでゾンビプロセスが発生するようになってしまいました。

以前のサーバーはFreeBSDでそのような事がなかったのですが、
新しいサーバーCentOS5になってから発生するようになってしまったのですが
どのような原因が考えらますでしょうか。

perlやSSIを使った時にだけ発生してしまいます。

色々しらべてはみたのですが、

mod_cgid.so

SSIではこれを無効にすればよいと言うのを見かけまして apache2のhttpd.confを見てみたのですが
LoadModule cg...続きを読む

Aベストアンサー

>ゾンビプロセス自体は、発生後に消える状態ではあります。

ゾンビプロセスの意味を理解されていますでしょうか?
消えるなら問題ありません。正常です。
通常、プロセスは終了するとプロセステーブル上でゾンビプロセスという状態になり、親プロセスからwaitされて、プロセステーブルから消えます。

「いままでゾンビプロセスでいる時間はミリ秒単位で、気づかなかったが、ゾンビプロセスでいる時間が長くなって、人間がpsでみるとしばしば見かけるようになった」
ということであれば、親プロセスの処理が重くなったとかでしょうかね。

Q繰り返し構造内での変数の確保の仕方

内部処理の質問になってしまうのですが、

sub Test{
 my($i);
 for($i = 0; $i < 10; $i++){
  my($flag) = 0;
  #何らかの処理...
 }
}

というものがあった場合、
for文中の$flagは繰り返しのたびにmy&変数開放を行ってしまうのでしょうか?

sub Test{
 my($i, $flag);
 for($i = 0; $i < 10; $i++){
  $flag = 0;
  #何らかの処理...
 }
}
の方が良いのでしょうか?

すごく疑問に思い、動作の軽そうな常に後者の方を利用していました。

お答えをよろしくお願いします。

Aベストアンサー

変数展開を行ってしまっていると思います。

for内及びfor外でmy宣言をした場合のそれぞれについて、試しに速度を測ってみたところ、かかる時間の比は

for外 : for内 = 4.60 : 6.10

という結果が得られました。
(for文のループを10000000回にしてためしました)

やはり外で宣言した方が役1.3倍くらい速いようです。
しかしそこまで劇的な差が無いですし、変数名の競合やバグ等の対策を考えればforループ内でしか使わない変数は(perlにおいては)forの中でmy宣言した方がいいのかもしれません。

Q動的なハッシュの配列を作成したい

#お世話になります。最終的には、下記のように配列の順番にハッシュを作成したいのですが、ご教授願えませんでしょうか

#!/usr/bin/perl

#想定される配列
@array=(0,2,4,6,8,1,3,5,7,9);

#下記が最終的に動的に作成したいハッシュの形です。
%List = (
'0' => [ (@array0_n) ],
'2' => [ (@array2_n) ],
'4' => [ (@array4_n) ],
'6' => [ (@array6_n) ],
'8' => [ (@array8_n) ],
'1' => [ (@array1_n) ],
'3' => [ (@array3_n) ],
'5' => [ (@array5_n) ],
'7' => [ (@array7_n) ],
'9' => [ (@array9_n) ], );

$a='array';
$n='_n';
foreach (@array){
#試行錯誤中...
print "\@{${a}[$_]{$n}}=@{${a}[$_]{$n}}";
}

__END__;

お忙しいかとは存じますが、よろしくお願いいたします。

#お世話になります。最終的には、下記のように配列の順番にハッシュを作成したいのですが、ご教授願えませんでしょうか

#!/usr/bin/perl

#想定される配列
@array=(0,2,4,6,8,1,3,5,7,9);

#下記が最終的に動的に作成したいハッシュの形です。
%List = (
'0' => [ (@array0_n) ],
'2' => [ (@array2_n) ],
'4' => [ (@array4_n) ],
'6' => [ (@array6_n) ],
'8' => [ (@array8_n) ],
'1' => [ (@array1_n) ],
'3' => [ (@array3_n) ],
'5' => [ (@array5_n) ],
'7' => [ (@array7_n) ],
'9' =>...続きを読む

Aベストアンサー

ざっと見たところ、リファレンスを使われたいのではないでしょうか。
それと、「最終的に動的に作成したいハッシュ」の%Listについては
'0' => [ (@array0_n) ],
と書かれている通り各keyに対してのvalueは配列が入る事になりますので
@array0_n~@array9_nの要素はハッシュ作成の処理を行う前に用意しなくてはなりませんね。

と、勝手に仮定しまして下記処理を書いてみました。

#---------------------------------------------------

@array=(0,2,4,6,8,1,3,5,7,9);

### 勝手に要素を用意しました
@array0_n=('a','b','c');
@array2_n=('d','e','f');
@array4_n=('g','h','i');
@array6_n=('j','k','l');
@array8_n=('m','n','o');
@array1_n=('p','q','r');
@array3_n=('s','t','u');
@array5_n=('v','w','x');
@array7_n=('y','z','aa');
@array9_n=('ab','ac','ad');

foreach(@array){
my $x="array$_\_n";
$List{$_}=[(@$x)];

print "@$x<br>";
}

#---------------------------------------------------

@arrayの要素番号0~ をハッシュのkeyとして、
valueを(@array要素番号_n)と言う配列名として、
実質、配列要素の順番にハッシュを作成した事になります。

もちろんハッシュを作成する順番の事であって、他の方が言われる通りハッシュのkey,valueの並び順を保障するモノではありません。

#下記が最終的に動的に作成したいハッシュの形です。
結果的に↑になっているのではないでしょうか。

ハッシュに対してシンボリックリファレンスを使って動的に配列を入れてます。(まずいですか?)
ご存知かとは思いますが%Listの各要素を確認するには
print $List{0}[1];
とかになります。

ちょっと質問の情報量が少なめなので
ほとんど推理に近い憶測で書いてみました。

ざっと見たところ、リファレンスを使われたいのではないでしょうか。
それと、「最終的に動的に作成したいハッシュ」の%Listについては
'0' => [ (@array0_n) ],
と書かれている通り各keyに対してのvalueは配列が入る事になりますので
@array0_n~@array9_nの要素はハッシュ作成の処理を行う前に用意しなくてはなりませんね。

と、勝手に仮定しまして下記処理を書いてみました。

#---------------------------------------------------

@array=(0,2,4,6,8,1,3,5,7,9);

### 勝手に要素を用意しま...続きを読む


おすすめ情報