こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

締切り済みの質問

Linux上でのTomcatのServletプロセスについて。

ご質問があります。

TomcatのServletプロセスについて悩んでいます。

Miracle Linuxをサーバとして、Apache-Tomcatを連携させたWebアプリの構築をしてます。

ここでまず一つ質問なのですが、Tomcatを起動させた時点でjavaのプロセスが24個も上がるのですが、これは普通なことなのでしょうか?ちなみに、メモリ消費量は約800Mです。

また次に、Tomcat内のServletに対してPostする度にプロセス数が増加し、メモリ消費量も1プロセスにつき300Kも消費してしまいます。そのため、どんどんリソースを消費し、メモリリークを起こしてしまうのですが、なぜかガベージコレクタが作動せず、延々とプロセスが溜まったままの状態になってしまいます。
通常は、ServletにアクセスしたらTomcatが常駐させてるプロセスを使用すると思うのですが、どこがおかしいのか全く分かりません。

どなたか、小さな事でもいいので助言をください。
よろしくお願いします。

投稿日時 - 2005-03-10 17:58:18

QNo.1261551

すぐに回答ほしいです

このQ&Aは役に立ちましたか?

22人が「このQ&Aが役に立った」と投票しています

回答(9)

ANo.9

> この数を越えた場合はどうなってしまうんですか?

以下は,Tomcat 4.1 の設定についての説明です.

HTTP/1.1 の場合
http://jakarta.apache.org/tomcat/tomcat-4.1-doc/config/coyote.html
JK2 の場合
http://jakarta.apache.org/tomcat/tomcat-4.1-doc/config/jk2.html

ここの,acceptCount のところに,その説明があります.
(どちらも同じ内容です.)

> Any requests received when the queue is full will be refused.

キューが一杯の場合,受信されたリクエストはすべて拒否されます.

参考URL:http://jakarta.apache.org/tomcat/tomcat-4.1-doc/config/coyote.html

投稿日時 - 2005-03-16 16:19:55

お礼

待ち状態のリクエストも一杯になるとその後は拒否されるんですね。
参考資料まで教えていただきありがとうございます。

とりあえず、色々と教えて頂いたことをすべて確認してみます。都合上、時間がかかってしまうのですが、確認した際にはご報告させていただきます。

分かりにくい質問に、長い時間丁寧に答えて頂き本当にありがとうございます。

投稿日時 - 2005-03-16 16:53:01

ANo.8

> たしかserver.xmlで設定でき、制限を越えた場合、待ち状態になりますよね?

そうです.
待ち状態になるリクエストの最大数も設定できます.

投稿日時 - 2005-03-16 15:19:19

補足

>待ち状態になるリクエストの最大数も設定できます.

この数を越えた場合はどうなってしまうんですか?

投稿日時 - 2005-03-16 15:34:07

ANo.7

> Webからアクセスして一定の処理を終えると画面が返ってくるのは確認済みです。

HTTPクライアント側への応答が終了した後,まだ何か処理をしていて,すぐに Tomcat に制御を戻していないという可能性が考えられます.
とにかく,きちんと doPost を終えているのか,この点を確認することだと思います.

> スレッドの数は,同時に処理されるリクエストの数によって決まります.

これについて補足ですが,最大のリクエストの数,とした方が,より正確かもしれません.
あと,スレッドの数には設定された制限がありますから,際限なく増えるわけではないです.

> あの、一応再度確認の意味でお聞きします。Linuxのスレッドはjavaのプロセス1つという事でよろしいですよね?

はい.Linux のスレッドは,ほぼプロセスと同じものです.
Javaの場合,Linux 上で,Javaのプログラム(ここではTomcat)がスレッドを1つ作ると,ps コマンド等からは,1つの java のプロセスとして見えます.

> やはり同時アクセスなしで、プロセスが増えるのはおかしいですよね。。。

そうですね.
起動時に,一度に一定数のスレッドを作るのは別にして,その後,必要もないのにスレッドを増やすことはないので,何かの理由でスレッドが利用中のままである可能性が高いと思います.

投稿日時 - 2005-03-16 13:35:35

補足

>とにかく,きちんと doPost を終えているのか,この点を確認することだと思います.

分かりました。確認してみます。

>あと,スレッドの数には設定された制限がありますから,際限なく増えるわけではないです.

たしかserver.xmlで設定でき、制限を越えた場合、待ち状態になりますよね?

>何かの理由でスレッドが利用中のままである可能性が高いと思います.

そうですね。。
スレッドやプロセスについては、SN1701さんのおかげでだいぶ理解できてきました。本当にありがとうございます。
ご指摘いただいた確認して見なければならない事は、事情によりすぐには実行できないのですが、必ず実行しますので遅くなってしまうかもしれませんが、その時はご報告させていただきます。

投稿日時 - 2005-03-16 14:09:46

ANo.6

> 作りの問題というよりは、他の例えばTomcatやApacheの設定まわりをもう少し詳しくみた方が良さそうですね。

doPost の終了時にログに出力して,確認してみて,問題なかったのでしょうか.もしもそうなら,自分で作ったプログラム以外のところに原因を求めるしかないでしょうね.
ただ,設定が原因でスレッドがたまるだけで再利用されなくなるというのは,ちょっと考えにくいのですが...

せめて切り分けをするために,Tomcat 単体で動かしてみて,同じ現象が起きるかどうか試すところから始めた方がいいかもしれませんね.
ただ,少なくとも私の環境では,Apache と連携してもこのような問題は起きていないのですが.

> 先ほど常駐していたスレッドがこのBというservletの起動に使われるのでしょうか?

スレッドのプールと servlet のインスタンスのプールは別の管理ですから,あるスレッドが特定の servlet 専用に使われるわけではありません.
ですから,同じスレッドが servlet A の実行にも,servlet B の実行にも使われます.
スレッドの数は,同時に処理されるリクエストの数によって決まります.

ちなみに私の環境では,初期のスレッド数以上の同時アクセスをしない限り スレッドの数は一定です.

> web.xmlに登録してないがためにスレッド起動時に新たに生成してしまうのでは

確かに,ちょっと考えにくいですね.
動作の点で違うのは,InvokerServlet という servlet を間に挟んで呼び出されることくらいです.
普通,呼び出される側の servlet から見て,動作が変わらないように実装されているはずです.

投稿日時 - 2005-03-16 12:13:16

補足

>doPost の終了時にログに出力して,確認してみて,問題なかったのでしょうか.

すみません。今は事情によりソースを書き換える事ができない状態にありますので、まだこの確認はしていません。ただ、Webからアクセスして一定の処理を終えると画面が返ってくるのは確認済みです。

>せめて切り分けをするために,Tomcat 単体で動かしてみて,同じ現象が起きるかどうか試すところから始めた方がいいかもしれませんね.

これも今すぐにできるわけではないのですが、問題解決の一要因として行ってみます。

>スレッドの数は,同時に処理されるリクエストの数によって決まります.

すごい分かり易いですね!理解できました。ありがとうございます。

>ちなみに私の環境では,初期のスレッド数以上の同時アクセスをしない限り スレッドの数は一定です.

そうですか。あの、一応再度確認の意味でお聞きします。Linuxのスレッドはjavaのプロセス1つという事でよろしいですよね?
やはり同時アクセスなしで、プロセスが増えるのはおかしいですよね。。。

投稿日時 - 2005-03-16 12:40:24

ANo.5

> 時間はかかりますがちゃんとレスポンスは戻ってきます。処理が終わってもTomcatに制御を返さない場合というのは起こりえるのでしょうか?

ちょっと考えにくいですね.普通に作れば,処理が終わったのなら制御を返すはずです.

ただし,時間がかかっていて処理が終わらないうちに,次のリクエストを受け取り,なおかつ利用可能なスレッドが残っていない場合,新しいスレッドが作られるでしょう.
毎回,確実に doPost を終えていて,同時に複数のリクエストを処理していないにも関わらず,次々スレッドが作られる場合は,別の原因を探す必要があるかもしれません.

> 確か今回のservletはすべてweb.xmlに登録してなかった気がするのですが、もしその場合セキュリティ以外に何か不都合などありますか?

InvokerServletを使っているんですよね.
基本的には,URLからServletにどうやってマッピングするか,その方法が違うだけですから,セキュリティ以外に特に不都合というものはないと思います.

気になるようでしたら,web.xml に登録して,試してみればよいと思います.

投稿日時 - 2005-03-15 19:18:24

補足

>毎回,確実に doPost を終えていて,同時に複数のリクエストを処理していないにも関わらず,次々スレッドが作られる場合は,別の原因を探す必要があるかもしれません.

そうですか。作りの問題というよりは、他の例えばTomcatやApacheの設定まわりをもう少し詳しくみた方が良さそうですね。

ちょっと基本的な質問なんですが、あるアクセスによりAというservletが起動し、処理を終えたとします。この場合Aというservletのスレッドはメモリに常駐され、次に同じくAというservletを使うアクセスがきた場合、この常駐済みのスレッドを使いますよね?
ここで、新たにBというservletを使うアクセスがきたとします。その場合、先ほど常駐していたスレッドがこのBというservletの起動に使われるのでしょうか?

>InvokerServletを使っているんですよね.
基本的には,URLからServletにどうやってマッピングするか,その方法が違うだけですから,セキュリティ以外に特に不都合というものはないと思います.

セキュリティ以外は関係ないんですね。
もしかしたら、web.xmlに登録してないがためにスレッド起動時に新たに生成してしまうのでは、という可能性もあるかなと思っていたのですが。違うみたいですね。

投稿日時 - 2005-03-16 10:02:33

ANo.4

> バッファやキャッシュは、psコマンド等で見た場合、javaプロセスとして表示されるのでしょうか?

ユーザモードの話ではないので,プロセスの一覧には出てきません.

コマンドラインから,free -k としてみてください.
キロバイト単位で,総メモリ量,使用メモリ量,使用可能メモリ量,バッファ,キャッシュのサイズ,加えて,バッファとキャッシュのサイズを,使用メモリ量と,使用可能メモリ量にプラス/マイナスした量が表示されます.

> では、GCが動作したか否かを見るには、ソースに直接書き込んでログを吐かせる、という具合にするのがベストでしょうか?

Runtime#freeMemory() を使えば,監視は出来ます.Runtime#totalMemory() の返す値も増える事がありますので,同時にモニタしなければなりません.

プログラムに埋め込んでしまわなくても,プロファイラなどのツールを使って,ヒープのサイズや使用量を監視することもできます.
私は,開発にEclipseを使っていますが,Eclipse用のプロファイラとして,Eclipse Profiler というプラグインがあります.
それには,ヒープサイズや使用量をモニタする機能があるので,それを使うことがあります.

http://sourceforge.net/projects/eclipsecolorer/

> 同時アクセスでなく1回1回アクセスしてテストしてみたんですが、毎回スレッドを新たに上げてしまいますね。。

確かにアプリケーションの作りの問題の可能性はありますね.

> スレッドがスタックしてしまい、利用中のままになってしまうような作り、というのは具体的にどのようにしたらそうなってしまうのでしょうか?

例えば,synchronized 等で,同期する箇所があったとして,それがデッドロックになっている場合が考えられます.
ただ,同時アクセスはしていないということですので,自前でスレッドを作っているのでなければ,起こらないような気がしますが.
他にも,非常に時間がかかる処理があって,そこで止まっている場合も同じような状態になるでしょう.
とにかく,doGetや,doPost が呼ばれた後,速やかに制御を返していない場合のすべてが該当します.
doGetや,doPost の最初と最後で,ログにメッセージを出力し,Tomcatに確実に制御を返しているかどうか,確認してみるのがよいかもしれません.

> 今回開発したWebアプリでは、フォーム毎にservletが起動する仕組みになっているので、実際servletの数はフォームの数に比例しているためかなりの数になっています。
> で、ビジネスロジックをほぼservletの中で行うようになっているのですが、この作りに問題がありそうですかね?

設計としてどうかという問題はともかく,その作り自体が,スレッドをスタックさせる直接的な原因になる可能性は低いと思います.

参考URL:http://sourceforge.net/projects/eclipsecolorer/

投稿日時 - 2005-03-15 16:25:29

補足

free -kですね。
コマンド調べればよいことを聞いてしまいすみません。
プロファイラーはぜひ試してみます!

synchronized は特に使っている箇所はないんですが、非常に時間のかかる処理をdoPostの中でやっているところもあります。その時間というのはデータ量によりまちまちなのではっきりとは言えないのですが。
ちなみにこの処理は、時間はかかりますがちゃんとレスポンスは戻ってきます。処理が終わってもTomcatに制御を返さない場合というのは起こりえるのでしょうか?とにかく一度ログで確認してみます。

>設計としてどうかという問題はともかく,その作り自体が,スレッドをスタックさせる直接的な原因になる可能性は低いと思います.

つくりの事で言い忘れてたんですが、確か今回のservletはすべてweb.xmlに登録してなかった気がするのですが、もしその場合セキュリティ以外に何か不都合などありますか?

よろしくお願いします。

投稿日時 - 2005-03-15 17:46:21

ANo.3

> 全メモリ量からスレッド数分のメモリを消費しているように見えます。

ps コマンド等で見たとき,各スレッドのメモリ使用量がすべて同じになっていませんか?
同じメモリ空間について表示しているからで,実際はその1つ分だけの消費です.

全メモリ量についてですが,バッファやキャッシュに使用されている分も物理メモリ使用量にカウントされているので,それは引いて考えないといけません.

ガーベージコレクタが動作していても,それは直接現れるわけではありません.
たとえ,ガーベージコレクタが回収しても,常にOSに返すわけではないので,ps コマンド等から見たJVMのメモリ使用量が頻繁に変化するわけではありません.

> 実際にはアクセスの度にスレッドを生成してしまい、常駐しているスレッドを使用してくれていないように見えてしまいます。これは、Webアプリの作りの問題でしょうか。

テストするときに,同時アクセスではなく,1回1回アクセスしてもそうなる場合,Webアプリケーションの問題である可能性はあります.
Webアプリケーションの作りの問題で,スレッドがスタックしてしまい,利用中のままになってしまうと,スレッドの最大数に達しない限り,Tomcat は新しいスレッドを作ってそちらで処理しようとします.
一度増えると減りませんから,どんどんスレッドが増えるように見えるでしょう.

投稿日時 - 2005-03-15 14:25:00

補足

>ps コマンド等で見たとき,各スレッドのメモリ使用量がすべて同じになっていませんか?

これについては今すぐ確認というのができませんので、後日確認してみます。

>全メモリ量についてですが,バッファやキャッシュに使用されている分も物理メモリ使用量にカウントされているので,それは引いて考えないといけません.

バッファやキャッシュは、psコマンド等で見た場合、javaプロセスとして表示されるのでしょうか?

>ガーベージコレクタが動作していても,それは直接現れるわけではありません.

では、GCが動作したか否かを見るには、ソースに直接書き込んでログを吐かせる、という具合にするのがベストでしょうか?

>テストするときに,同時アクセスではなく,1回1回アクセスしてもそうなる場合,Webアプリケーションの問題である可能性はあります.

同時アクセスでなく1回1回アクセスしてテストしてみたんですが、毎回スレッドを新たに上げてしまいますね。。

>Webアプリケーションの作りの問題で,スレッドがスタックしてしまい,利用中のままになってしまうと,スレッドの最大数に達しない限り,Tomcat は新しいスレッドを作ってそちらで処理しようとします.

スレッドがスタックしてしまい、利用中のままになってしまうような作り、というのは具体的にどのようにしたらそうなってしまうのでしょうか?

今回開発したWebアプリでは、フォーム毎にservletが起動する仕組みになっているので、実際servletの数はフォームの数に比例しているためかなりの数になっています。
で、ビジネスロジックをほぼservletの中で行うようになっているのですが、この作りに問題がありそうですかね?

よろしくお願いします。

投稿日時 - 2005-03-15 14:49:34

ANo.2

Linuxでは,スレッドはプロセスによって実現されています.ですから,Javaでスレッドを作った場合,ps コマンド等から見るとプロセスに見えます.
つまり,24個あるというプロセスは,実はスレッドです.
また,スレッド同士はメモリ空間を共有していますから,各スレッドの使用メモリ量を足しても意味がありません.

http://japan.linux.com/kernel/internal22/node26.shtml
http://www.linux.or.jp/JF/JFdocs/Secure-Programs-HOWTO/processes.html

> プロセスが溜まったままの状態

Tomcatは,アクセスがあったときに毎回スレッドを作るのではなく,一度スレッドを作ったら使い回しますので,スレッドの数は減るとは限りません.

参考URL:http://japan.linux.com/kernel/internal22/node26.shtml

投稿日時 - 2005-03-13 19:34:04

補足

返事が遅くなりまして申し訳ありません。

>スレッド同士はメモリ空間を共有していますから,各スレッドの使用メモリ量を足しても意味がありません.

psコマンドやLinuxのアプレットにてメモリ使用量を確認したのですが、全メモリ量からスレッド数分のメモリを消費しているように見えます。スレッドが24個もあるので、全体から見るとかなりのメモリを消費しているように見えるのですが。。。

>Tomcatは,アクセスがあったときに毎回スレッドを作るのではなく,一度スレッドを作ったら使い回しますので,スレッドの数は減るとは限りません.

これは私もそう認識していたのですが。
実際にはアクセスの度にスレッドを生成してしまい、常駐しているスレッドを使用してくれていないように見えてしまいます。これは、Webアプリの作りの問題でしょうか。

よろしくお願いします。

投稿日時 - 2005-03-15 10:31:01

ANo.1

>Tomcatを起動させた時点でjavaのプロセスが24個も上がるのですが、これは普通なことなのでしょうか?
>ちなみに、メモリ消費量は約800Mです。

正直な話、ありえねー!って感じです。

>Tomcat内のServletに対してPostする度にプロセス数が増加し

スレッドじゃなくて、プロセスですよね?
やっぱりありえねー!です。

>小さな事でもいいので助言をください。

ほんとにアドバイスのみですが、以下のことを確認ください。

1.Apache連携しないで、Tomcatのみ(8080ポート)で動かしたらどうなりますか?
2.Tomcatの標準のWebアプリのみで起動したらどうですか?

以下は想像で書いています。
まずプロセスが上がるということは、Webアプリの中でRuntime.getRuntime().exec()を使って、Tomcatから更に別のjava VMを起動しているということはありませんか?
通常ガーベッジコレクタが動くのは、java VMの中のインスタンスのみです。従って、別プロセスで上がってしまったら、他人のVMまでは面倒みれません。
起動した本来のTomcatのjavaプロセスから見て、別のjava VMは、Windowsでいうところの別exeと同じですので、javaとはいえ全然無関係な世界です。普通だったら、同じVM内でインスタンス生成して使うと思うのですが。

謎ですね。

唯一考えられるのは、同じVMだとメモリが一杯になるので、わざと別VMを起動していたりして・・・。

投稿日時 - 2005-03-12 09:28:25

お礼

返事が遅くなってしまい申し訳ありません。

Webアプリの中でRuntime.getRuntime().exec()で別VMを起動ってことは特にやってないですね。。。

何らかの理由で別VMとして起動しているのかもしれませんね。

今すぐにできる環境ではないのですが、1と2を確認してみたいと思います。

ありがとうございました!

投稿日時 - 2005-03-15 10:27:40

あなたにオススメの質問