[Java News] → [Java Performance Tuning] → [no.45] [no.46] [no.47]

Java Performance Tuning Newsletter no. 47

さて、5.0がリリースされましたね。 個人的には Sun がこれを「5.なんとか」と呼ぶことには何らこだわりはありません。 私にとって名前は問題ではないのです。 問題なのはこのリリースのパフォーマンスと堅牢性です。 そして残念なことに(毎度のことですが)、速報された挙動をみていると ".0" リリースというのは安定したテストを行うことはできても、安定した運用には使えないということです。

これは Sun の責任ではありません。私たちの業界の風土病なのです。 ".0" リリースがとても安定していて、リリース直後に ".1" やら ".0.1" やら、さもなければ似たようなパッチがリリースされなかった、最近のソフト製品といえば何があるでしょう? ないとはいいませんが、その数はとても少ないし、時期もまばらです。 これはバグだらけのソフトをリリースしても、何のペナルティーもないからです。 ハードウェアエンジニアがいいかげんなハードウェアを世に送り出したら、その製品を回収して新しいものを再リリースしなくてはいけません。 ふつうなら相当のコストがかかる作業です。 ソフトウェアエンジニアは単にパッチや新バージョンを再発行するだけで、ふつうなら事足ります。 コストも非常に安く済みます−−ベンダーにとっては、ですが。

これは問題なのでしょうか? ".0" リリースに関する限り、実際には問題ではありません。 それが本当はベータリリースであることはみんなわかっています。 しかしよく引き合いに出される「保守コストは開発コストの4倍」という数字は、十分な堅牢性と性能テストを計算に入れたときの本当のソフトウェアのコストの大きさを示しています。 こういう形でソフトウェアの本当のコストを隠すことに問題があるかどうかは、私にはわかりません。 ただ、誰もが自分のソフトウェアに完全に堅牢かつ高性能な ".0" バージョンを作れるほどの値段を付けたとしたら、私たちの業界は今よりもずっと小規模で特殊なものになっていただろう、と思います。

今回のニュースレターでも、いつもの記事やニュースをリストアップしています。 恒例のセクションもあります。 Kirk のまとめ では、5.0 のパフォーマンス、びっくりするようなメモリ性能の違い、J2EE の監視などを取り上げています。 そのほかにも、繰り返されてはいけない習慣に新たなクソッタレ大賞を贈呈しています。 ジャヴァ・ザ・ハット は「バカ度」ボトルネックを紹介してくれます。 今月の質問 では EJB と JDBC 直接呼び出しの性能を比較します。

今月は java.util.concurrent 関連の記事に力を入れてみました。 そのため、たくさんの java.util.concurrent のパフォーマンス tips 記事が簡潔にまとめられています。 また、先月の パフォーマンス・インタビュー の記事をここでリストするのを忘れてしまっていました。 見逃した方のために、ここにリンクを書いておきます。

最新ニュース

Javaパフォーマンスチューニング関連ニュース

ツール紹介

最近の記事

Jack Shirazi


Kirk のまとめ

私がパフォーマンスチューニングの講義をしていたクライアントから、講義の中で JDK 5.0 を使えないかと聞かれました。 ジャックと私はぜひそうしようと考えました。 私たちだって、受講者のみなさんにはなんでも実験してみることをお勧めしているわけですし。 ほかの多くの講座でもそうですが、今回も一週間の講義の中で、他のものよりも多く取り扱う特別なアプリケーションがあります。 私がテストしたのはこのアプリケーションでした。

そのアプリケーションはクライアント、サーブレット、データベースの3層ものです。 私は 1.4 でサーブレットエンジンを起動し、ウェブから負荷をかけるスクリプトをしかけました。 CPU 使用率とレスポンス時間をおおざっぱに把握してから、サーブレットエンジンを 5.0 で起動し直しました。 5.0 では CPU 使用率が 5% 多いこと、全体的なレスポンス時間が 10% ほど増えていることを発見しました。 5.0 に性能アップを期待している方は、次のリリースを待った方がいいかもしれません。 歴史的にみれば .0 リリースはいつも直前のリリース版よりも多少性能が劣る傾向があるためです。

JavaGaming.org

JavaGaming では階層化コンパイルについて興味深い説明がありました。 いまのところ、HotSpot プロファイラはアプリケーションの中で非常に頻繁に実行される部分を発見しようとします。 それが見つかったら、JIT がコードの中の「熱い」部分をコンパイルする命令を受けます。 JIT の挙動とは、速度と生成されるネイティブコードの品質とのトレードオフです。 階層化コンパイルではコード生成の速度が遅い代わりに、より高品質なネイティブコードを生成できます。 逆に出力物の質が落ちる代わりに、高速にコードを生成することもできます。 なぜこうしたことが起きるのかについては現在でも調査が進められています。 近いうちにそれが公開されることはないと考えていいでしょうが、待ち遠しい情報だと思います。

別の投稿者は 'new byte[1000000][1]' と 'new byte[1][1000000]' では、それぞれどれだけのメモリを確保するのかを知りたがっていました。 その差が 1.6MB と知ったら、驚きますか? いえいえ、見間違いではありませんよ。 前者の宣言では後者よりも 1.6MB よけいにメモリを使うのです! 覚えておきたいのは、配列はふつうの Java オブジェクトと同様に扱われるということです。 大きさが 1バイトの配列を 1000000個持つこともできるし、大きさが 1000000バイトの配列を1個持つこともできるのです。 さあ、どちらを選びますか?

最後はゲームプログラマが始めたスレッドですが、こんなアドバイスがありました。 「だいたいの場合、すべてのガベージがかなり頻繁に削除され、古い世代に送られるものがほとんどないように、若い世代の回収機構をチューニングできなくてはいけません」 問題は、いったいどうやってそんなことをするのか、ということです。 私の経験では、生存オブジェクト用のスペースを増やすのが一番いいようです。 Eden と survivor spaces はすべて若い空間から取り分けられていて、survivor space の大きさを増やせば Eden の大きさは小さくなります。 Eden の全体的サイズを減らすと GC が頻繁に起きるようになります。 survivor spaces を大きくするとオブジェクトは(GC のコストがずっと低い)若い世代に残るようになります。 他のすべてのパフォーマンスチューニングのアドバイスもそうですが、効果は必ずしもあるとは限りません。

The Server Side

The Server Side の最初のスレッドでは、J2SE5.0 を使おうという試みのレポートがありました。 Orion サーバーを Windows と Linux で使ってみようという彼の試みは、どうやら性能が明らかに低下するという結果に終わったようです。 一つ指摘すると、本当にこの結果が 5.0 への移行によるものなのか、別の問題によるものなのか、判断するために必要な情報がこの投稿には不足しています。

ある投稿では、マイクロソフトの NTLM セキュリティ機構と統合された J2EE 監視ツールはどれを使えばよいのか、という質問がありました。 こちらの回答 http://www.theserverside.com/discussions/thread.tss?thread_id=28863 を見ると、太っ腹なことにそのような監視ツールの完璧な市場調査が含まれていました。 優しい人々ですね!

The Server Side からご紹介する最後の投稿は、内側からアプリケーションサーバの負荷テストを行うツールを探すにあたって、助力を求めるものでした。 アプリケーションサーバの内側からユニットテストを行うのは便利ですが、アプリケーションサーバの負荷テストを行うのに同じアプローチが有効かというと疑問です。 アプリケーションサーバの内側から動く、という売り文句を持つ負荷テストツールはひとつもありませんでしたが、驚くにはあたらないでしょう。

The JavaRanch

JavaRanch からは、もう始まってから8ヶ月にもなるスレッドを紹介します。 「Enumeration と Iterator、どっちが速いのか」を決める議論にぽつぽつとデベロッパーが挑戦するたびに、このスレッドは息を吹き返してきました。 たいていの初期のベンチマークと同様、これも問題だらけでした。 後に続いた投稿の中で、実際のベンチマーク結果を記したものは一つもなかったので、それら投稿者が得た計測値が当初よりもましな結果であったかどうかはなんともいえません。 ある投稿では、Enumeration を使うとガベージコレクタが「より静かに」なるという主張がありました。 これはこれで「このベンチマークにガベージコレクションは含まれるべきなのか」という興味深い問題提起になっています。 アルゴリズム上、一時的に生成されるオブジェクトが多く、それらのオブジェクトのライフサイクルを管理するためのコストよりも多いのであれば、ベンチマークに GC の時間を含めるべきだという主張は正当なものです。 問題は参照がはずれたオブジェクトを持っている、という点以外にガベージコレクションとアルゴリズムは関係がないということです。 そこに、ヒープにこれ以上オブジェクトを置く空きメモリがないときにガベージコレクションが発生するという事実が組み合わさりました。 すべてヒープの大きさに依存するのであれば、ヒープの大きさはどのくらいにすればいいのでしょうか? 通常のチューニングであればシーケンシャル GC のオーバーヘッドが 5% 以下になるようガベージコレクタとメモリ空間を調整することになるでしょう。 しかしこのような手法をパフォーマンス測定のためのマイクロベンチマークで使用したら、結果の比べようがありません。

そもそもの質問は「どちらの実装がより速いか」(およそどの程度速いのかを知りたい、という前提ですが)ということなので、同じ設定で両方ともベンチマークを走らせればよいでしょう。 次のステップは、Iterator の実行時、あるいは Enumeration の実行時に GC が起きなくなるまで VM をチューニングすることです。 Enumeration が最も速いと仮定するなら、これを基準にします(ここでは GC なしで動作する、という意味です)。 もし GC が Iterator のテスト中に発生したら、その値は Enumeration の実行に必要な水準よりも多いということになります。 完全な計測方法とはいえませんが、質問の答えについて大体の見当はつけられるはずです。

別の投稿では、新米が静的変数とローカル変数の性能の違いをマイクロベンチマークで計測していました。 気が確かである限り、私はよりよい設計となるほうを支持します。 言い方を変えると、静的変数の方が速いかもしれませんが、そんなことはどうでもいいのです。 私なら、設計上必要であるなら静的変数を使います。 もしローカル変数を使うことがボトルネックになっているとわかったら、どうしてそんなことになるのかと Sun を問いつめてやりますよ!

また別のスレッドでは、プロセッサのスピードは限界に近づいているんじゃないか、という問いにまつわる興味深い議論がありました。 結論は出ていませんが、いくつかおもしろい論点が持ち上がっています。 まず、サイズは小さくなってはいるが、相対的な速度の向上は期待されているほど大幅ではないということです。 サイズの面では IBM が期待値を満たしましたが、予期される性能目標には到達していないし、歩留まりはどうやら非常に低いようです。 インテルでさえつい最近、4.0GHz は作らない代わりに 3.6GHz の改良に集中することを発表しました。 これ以上スピード競争に突き進む前に、ここで何らかのリファクタリングが必要と感じたのかも知れません。 一つ明らかなことは、プロセッサの速度はパフォーマンスを測る指標の一つでしかないと言うことです。 たとえば私の Pentium-M 1.6GHz は Pentium IV 2.4GHz と同等とされています。 最後に一言。SEDA(Staged Event Driven Architecture) に対する興味深い言及があります(訳注:複雑なイベント駆動アプリケーションを、キューで接続された複数のステージに分解する手法。スレッドベースの並列動作モデルのオーバーヘッドを解消するとともに、アプリケーションロジックからイベントとスレッドスケジューリングを分離できる。元の論文:http://www.eecs.harvard.edu/~mdw/proj/seda/)。 さらなる Java パフォーマンスへの賛辞になりますが、このサイトにおける主張では Java での実装が C/C++ での実装と同等、ないしそれ以上の速度を達成したとのことです。 動的コンパイルに拍手を送りましょう! これが実験環境下での単なる演習だと思っている方は考え直した方が良いですよ。 彼らのフレームワークをベースにしたアプリケーションのリストには LimeWire、TerraLycos、Apache Excalibur Event Package、SwiftMQ などのきわめてスケーラビリティと並列稼働性の高いアプリケーションが並んでいます。

最後に一言

最近になって我がマイクロソフトが出資したような調査に大企業が出資するとき、その結果について運を天に任せるような会社はないであろうことに The Server Side も気づくはずだ。 2001年に初めての調査結果が発表されたとき、普通の人なら誰でもそう思ったことでしょう。 マイクロソフトは J2EE 勢力を浮き足立たせることで、またしてもマーケティングにおいて成功を収めた、と私は敢えて言わねばなりません。 TMC と Tyler Jewel はまだわかっていないんでしょうか? マイクロソフトや他の大企業は、この手の調査を運任せにしたりはしないのですよ! 調査が承認を受けたりする前に修正されてしまう以上、なぜ TMC はただでさえ危うい自社の信頼性をこれ以上傷つけるようなことをするのでしょう? 最初の調査から生じた作為的な大論争の記憶が薄れてしまわないよう、TMC と Tyler Jewel には誰も欲しがらない Meadow Muffin 賞を贈呈します。 おめでとう諸君。またしても糞を踏んじゃったようですね。

Kirk Pepperdine.


ジャヴァ・ザ・ハット(Hutt の日記)

9月8日。
プロジェクト Xenon をチューニングしなくてはいけなかった。 いや、実際には性能目標も SLA もクリアできていたし、1年半前にプロジェクトが立ち上がってからというもの、性能テストはずっと走らせ続けていた。 でもその辺は基本のキなのだ。 つい最近まで、顧客の手には最低限のスケルトン機能しか入っていないシステムしかなかったのだから。 チューニングが必要という話は、別に驚くことじゃない。それなりに複雑なシステムで、どの時点でもパフォーマンスチューニングの必要がない代物なんてお目にかかったことがないし、俺の前倒しのアプローチのおかげで、この問題をスケジュールの早い段階で発見できていたからだ。

9月15日。
予備試験の結果、16の主たる性能目標があることがあきらかになった。 それぞれ CPU、メモリ、ディスク I/O、ネットワーク I/O、データベース I/O、そして GC にちらばっている。 中には2桁の性能改善が必要なものもあった。 すでにいくつか会議をやって、目標の優先順位付けを行った。 過去の経験からすると、システムのチューニングや機能追加をすればパフォーマンスのボトルネックは変わるのだから、どうせ順番なんて関係ないのだが。 だが結局、この手の目標を決めなければ進捗会議で言い争うため - おっといかん、話し合うため - のネタがなくなってしまうのだ。

9月22日。
Weevil をだまくらかして、1月頭から Xenon のパフォーマンスに関して品質保証の協力者になってもらうことにした。 俺はスケジュール上、Xenon のパフォーマンス管理のために余分のQAリソースが必要だと公言していたので、Weevil の増員とか開始時期について手を打ったというわけ。 あいつはこの仕事がステップアップだと思っているようだ。 マネジメント的に言えば、基本的に俺がやるはずの仕事をしているんだからな。 だがあいつはこの手の仕事の素性を理解していない。 俺の見積もりでは、俺が勝手に「バカ度」ボトルネックと名付けたものが見つかるので、第4四半期には相当でかいパフォーマンスの伸びがあるはずだ。 これが何かというと、単に誰かが馬鹿なコードを書いたせいで、パフォーマンスが桁単位で遅くなる、というものだ。 開発の初期段階ではいつもこの手のコードが見つかる。 そして Weevil が仕事を引き継いだ瞬間にこれを駆逐し、俺が「シーソー」と呼んでいるチューニング段階に突入させる。 これは機能追加・機能変更・バグ修正があまりに速いペースで続いているので、パフォーマンスチューニングがまったく進まない、という段階のことだ。 なぜなら「バカ度」ボトルネックはすでになくなっているからだ。 この段階では、どんなチューニングをしても適用する場所が見当違いだったり、機能変更やバグ修正で上書きされたり、ほかの場所での変更のせいで無駄になったりする。 「毒入りの聖杯」という言葉を聞いたことはあるだろうか。 へっへ、あいつが引き継いでから性能改善のプロセスががた落ちした理由は、あいつには理解し始めることもできないだろうさ。

Javva The Hutt.


今月の質問 : 性能対決 EJB 対 JDBC 直接呼び出し

EJB を使うのと JDBC を直接使うのとではどちらが性能上有利ですか?

この質問はディスカッショングループで良く見られますし、私達のところにも何度も送られて来ています。 これは J2EE の性能に関する質問のうち最も頻繁に繰り返されるものの一つなのです。

こう言っておくのが無難でしょう。 「ほとんどの場合、EJB の性能は直接呼び出しとほぼ同等と成り得ますが、最悪の場合はかなり遅くなります。」その理由は?
どちらを使うにせよ、SQL を使ってオブジェクトに含まれるデータをデータベースへ格納しなければなりません。 EJB アーキテクチャを使用するということは、あなたと格納したいデータとの間にフレームワークを配置するということです。 当然、JDBC をそのまま使うのに比べて EJB を使う場合の付加的なコストは避けられません。

しかし、業界では EJB 技術はそのコストに十分見合うものだと考えられています。 多くのアプリケーションでは EJB を使うことで得られる恩恵の方が性能上のコストよりも重んじられます。 さらに言えば、単純な JDBC と EJB の比較においては、あなたの書く JDBC のコードが EJB が生成するコードとが同じくらい効率的だと前提されています。 その前提は決して確実なものではありません。 コンテナベンダは最適な SQL を生成するエキスパートを抱えているものです。 そして、EJB コンテナには、その上で動作している EJB に一括 (in groups)、または並列(concurrently)処理という、バルク実行による処理効率の最適化をかけるタイミングを判断できるという利点があります。 またコンテナはデータの差分やダーティ/非ダーティに基づく最適化も適用できます。JDBC のコードにおいてもこれらの最適化処理は可能ですが、あなたの永続化フレームワークは更に複雑になるでしょう。 加えて、コンテナの永続化フレームワークを構築する時に永続化フレームワークの専門家が負うべき責任をあなた自身が負うことになります。

現実的には EJB はそれを必要とするようなアプリケーション (リクエストを並行処理するトランザクショナルな J2EE アプリケーション) に対しては、EJB のアンチパターンにはまってしまうようなことがない限りは十分な性能を発揮するでしょう。 そのために FastLane Reader のような EJB の性能を向上させるパターンの助けを必要とすることもあるでしょう。 しかし、もしあなたが同等のことを JDBC でもしようとしているのなら、JDBC を直接扱うときの素直なやり方に従うべきです。

まとめると、素の JDBC は、アプリケーションに対して最適な JDBC コードを作れる限りにおいては EJB を使うよりも効率的です。 その一方で、JDBC コードの複雑さを自分で保守するか EJB コンテナにやってもらうかというトレードオフが有ります。 また、EJB を使う時には、性能劣化を引き起こすアンチパターンを避けることと、EJB の良く知られた非効率な部分を取り除くための性能を強化するパターンを使うことの両方に気を配る必要が有ります。

The JavaPerformanceTuning.com team


Tips(技法・裏技)

http://today.java.net/pub/a/today/2004/08/02/sync1.html
同期処理のABC、パート1
(最終更新 August 2004, 追記 2004-10-31, 著者 Jeff Friesen, 出典 java.net). Tips:

http://today.java.net/pub/a/today/2004/09/15/sync2.html
同期処理のABC、パート2
(最終更新 September 2004, 追記 2004-10-31, 著者 Jeff Friesen, 出典 java.net). Tips:

http://www.oreilly.com/catalog/jthreads3/chapter/index.html
Java スレッド 第3版 第5章
(最終更新 2004-09, 追記 2004-10-31, 著者 Scott Oaks, Henry Wong, 出典 O'Reilly) Tips:

http://www.oreilly.com/catalog/jthreads3/chapter/index.html
Java スレッド 第3版 第6章より抜粋

(最終更新 2004-09, 追記 2004-10-31, 著者 Scott Oaks, Henry Wong, 出典 O'Reilly). Tips:

http://www.developer.com/java/ent/article.php/3412021
キャッシュによる J2EE アプリケーションのパフォーマンス向上

(最終更新 2004/9, 追記 2004/10/31, 著者 Scott Robinson , 出典 developer.com). Tips:

http://dev2dev.bea.com/community/architect/articles/baumgarten.jsp
J2EE デザインパターン
(最終更新 2003/11, Added 2004/10/31, 著者 Alan Baumgarten, 出典 BEA). Tips:

Jack Shirazi


Last Updated: 2005-10-18
Transcopyright 2001-2005 JavaPerformanceTuning translation team. All Rights Reserved.
contributors: Tsuyoshi FUKUI, Akky AKIMOTO Hiroki, Yasunori Taniike, Nobuyuki Hirashima, Yoshie HAMANA, Yukio Andoh
Copyright © 2000-2005 Jack Shirazi. All Rights Reserved.
Original URL: http://www.JavaPerformanceTuning.com/newsletter047.shtml
URL: http://javanews.jp/javap/newsletter047.html
Japanese version maintained by Yukio Andoh - andoh@javanews.jp