ホームページ Java &#&チュートリアル Java のパフォーマンスに関する 9 つの誤解

Java のパフォーマンスに関する 9 つの誤解

Nov 26, 2016 am 11:32 AM
java Javaのパフォーマンス

Java のパフォーマンスは、ある種の黒魔術として知られています。その理由の 1 つは、Java プラットフォームが非常に複雑であり、多くの場合、問題を特定するのが難しいことです。ただし、応用統計や経験的推論に頼るのではなく、知恵と経験に基づいて Java のパフォーマンスを研究するという歴史的な傾向もあります。この記事では、最もばかばかしいテクノロジー通説のいくつかが誤りであることを暴きたいと思っています。

1. Java は遅い

Java のパフォーマンスについては多くの誤解がありますが、これは最も時代遅れであり、おそらく最も明らかです。

1990 年代から 2000 年代初頭にかけて、Java が時々遅くなったのは事実です。

しかし、それ以来 10 年以上にわたって仮想マシンと JIT テクノロジが向上し、Java の全体的なパフォーマンスは現在非常に優れています。

6 つの独立した Web パフォーマンス ベンチマークにおいて、Java フレームワークは 24 テスト中 22 でトップ 4 にランクされました。

JVM はパフォーマンス プロファイリングを使用して、一般的に使用されるコード パスのみを最適化しますが、最適化の効果は明ら​​かです。多くの場合、JIT コンパイルされた Java コードは C++ と同じくらい高速であり、そのような状況はますます増えています。

それにもかかわらず、Java プラットフォームは遅いと考える人がいます。これは、Java プラットフォームの初期バージョンを経験した人々の歴史的な偏見に由来している可能性があります。

結論を出す前に、客観性を保ち、最新のパフォーマンス結果を評価することをお勧めします。

2. Java コードの 1 行を単独で表示できます

次の短いコード行を考えてみましょう:

MyObject obj = new MyObject();

Java 開発者にとって、このコード行が必ずオブジェクトを割り当て、適切なコンストラクターを呼び出します。

これに基づいてパフォーマンスの境界を導き出すことができるかもしれません。このコード行によって確実に一定量の作業が実行されると想定し、この推定に基づいてパフォーマンスへの影響を計算してみます。

実は、この理解は間違っています。それは、どんな仕事であっても、どんな状況下でも実行されるという先入観を与えます。

実際、javac コンパイラーと JIT コンパイラーは両方とも、デッドコードを最適化して取り除くことができます。 JIT コンパイラーに関する限り、プロファイリング データに基づいて、予測を通じてコードを最適化することもできます。この場合、このコード行はまったく実行されないため、パフォーマンスには影響しません。

さらに、JRockit などの一部の JVM では、JIT コンパイラがオブジェクトの操作を分解することもできるため、コード パスがまだ有効な場合でも割り当て操作を回避できます。

ここでの教訓は、Java のパフォーマンスの問題を扱うときはコンテキストが非常に重要であり、時期尚早な最適化は直感に反する結果を生み出す可能性があるということです。したがって、時期尚早に最適化しないことが最善です。代わりに、常にコードを構築し、パフォーマンス チューニング手法を使用してパフォーマンスのホット スポットを特定し、改善します。

3. マイクロベンチマークはご想像どおりです

上で見たように、コードの小さな部分を調べることは、アプリケーションの全体的なパフォーマンスを分析するほど正確ではありません。

にもかかわらず、開発者はマイクロベンチマークを書くのが大好きです。基盤となるプラットフォームの一部をいじるのはとても楽しいようです。

Richard Feynman はかつてこう言いました。「自分を騙さないでください。最も騙されやすいのはあなたです。」 この文は、Java マイクロベンチマークの作成を説明するのに最適です。

適切なマイクロベンチマークを作成することは非常に困難です。 Java プラットフォームは非常に複雑であり、多くのマイクロベンチマークは、Java プラットフォームの一時的な影響やその他の予期しない側面しか測定できません。

たとえば、経験がない場合、作成するマイクロベンチマークは時間やガベージ コレクションを測定するだけで、実際の影響要因を捉えていないことがよくあります。

実際のニーズがある開発者と開発チームのみがマイクロベンチマークを作成する必要があります。これらのベンチマークは完全に公開され (ソース コードを含む)、再現可能であり、ピアレビューとさらなる精査の対象となる必要があります。

Java プラットフォームの多くの最適化では、統計的な実行と単一の実行が結果に大きな影響を与えることが示されています。正確で信頼できる答えを得るには、単一のベンチマークを複数回実行し、結果を集計する必要があります。

読者がマイクロベンチマークを作成する必要性を感じている場合は、Georges、Buytaert、および Eeckhout による論文「統計的に厳密な Java パフォーマンス評価」が良いスタートとなります。適切な統計分析がなければ、私たちは簡単に誤解されてしまいます。

その周囲には、よく開発されたツールとコミュニティがたくさんあります (Google の Caliper など)。本当にマイクロベンチマークを作成する必要がある場合は、自分で作成しないでください。必要なのは同僚の意見や経験です。

4. パフォーマンスの問題の最も一般的な原因はアルゴリズムの遅さです

開発者 (および一般の人々) の間には、自分が制御するシステムの一部が重要であると考えるという、非常に一般的な認知エラーがあります。

この認識上の誤りは、Java のパフォーマンスについて議論するときにも反映されます。Java 開発者は、アルゴリズムの品質がパフォーマンスの問題の主な原因であると信じています。開発者はコードについて考えるので、自然と独自のアルゴリズムについて考える傾向があります。

実際、一連の現実のパフォーマンス問題に対処するときに、アルゴリズムの設計が根本的な問題であると人々が気づく確率は 10% 未満です。

逆に、ガベージ コレクション、データベース アクセス、構成エラーは、アルゴリズムよりもアプリケーションの速度低下の原因となる可能性が高くなります。

ほとんどのアプリケーションは比較的少量のデータを処理するため、メインのアルゴリズムが効率的でなくても、通常は深刻なパフォーマンスの問題を引き起こしません。確かに、私たちのアルゴリズムは最適ではありませんが、それでも、このアルゴリズムによって引き起こされるパフォーマンスの問題は比較的小さく、アプリケーション スタックの他の部分によってさらに多くのパフォーマンスの問題が発生します。

したがって、私たちの最善のアドバイスは、実際の運用データを使用して、パフォーマンスの問題の本当の原因を明らかにすることです。パフォーマンス データを測定します。推測しないでください。

5. キャッシュはすべての問題を解決できる

「コンピューターサイエンスにおけるすべての問題は、中間層を導入することで解決できる。」

デビッド・ウィーラーのプログラマーのモットー (インターネット上では、少なくとも他の 2 台のコンピューターによるものと考えられています)科学者)は、特に Web 開発者の間で非常に一般的です。

既存のアーキテクチャが完全に理解されておらず、分析が行き詰まっている場合、多くの場合、「キャッシュですべての問題を解決できる」という誤った考えが醜い頭をもたげます。

開発者の意見では、恐ろしい既存のシステムに対処する代わりに、前面にキャッシュのレイヤーを追加して既存のシステムを隠し、最善の結果を期待する方がよいと考えています。間違いなく、このアプローチではアーキテクチャ全体がより複雑になるだけであり、引き継ぐ次の開発者がシステムの現在の状態を理解しようとすると、状況はさらに悪化するでしょう。

大規模で設計が不十分なシステムは、全体的な設計が欠如していることが多く、一度に 1 行のコードと 1 つのサブシステムが記述されます。ただし、多くの場合、アーキテクチャを単純化してリファクタリングするとパフォーマンスが向上し、ほとんどの場合、理解しやすくなります。

そのため、本当にキャッシュを追加する必要があるかどうかを評価するときは、まず、キャッシュ層によってもたらされる本当の価値を証明するために、いくつかの基本的な使用統計 (ヒット率やミス率など) を収集する計画を立てる必要があります。

6. すべてのアプリケーションは、Stop-The-World 問題に注意する必要があります

Java プラットフォームには、ガベージ コレクションを実行するために、すべてのアプリケーション スレッドを定期的に一時停止する必要があるという変更できない事実があります。これは、実際の証拠がない場合でも、Java の重大な欠点として引用されることがあります。

実証研究によると、デジタル データ (価格変動など) が 200 ミリ秒に 1 回よりも頻繁に変化すると、人々はそれを正常に認識できなくなります。

アプリは主に人間が使用することを目的としているため、200 ミリ秒以下の Stop-The-World (STW) は通常影響を及ぼさないという有用な経験則があります。一部のアプリケーション (ストリーミング メディアなど) には、より高い要件が必要な場合がありますが、多くの GUI アプリケーションではそれは必要ありません。

一部のアプリケーション (低レイテンシー取引やマシン制御システムなど) は 200 ミリ秒の一時停止を許容できません。このタイプのアプリケーションを作成していない限り、ユーザーがガベージ コレクターの影響を感じることはほとんどありません。

アプリケーション スレッドの数が物理コアの数を超えるシステムでは、オペレーティング システムが CPU へのタイムシェアリング アクセスを制御する必要があることに注意してください。 Stop-The-World というと恐ろしく聞こえますが、実際には、どのアプリケーション (JVM であっても他のアプリケーションであっても) は、希少なコンピューティング リソースをめぐる競合の問題に直面する必要があります。

測定しない場合、JVM がアプリケーションのパフォーマンスにさらにどのような影響を与えるかは不明です。

とにかく、GC ログをオンにして、一時停止時間が実際にアプリケーションに影響を与えているかどうかを確認してください。手動またはスクリプトやツールを使用してログを分析し、一時停止時間を決定します。次に、それらが実際にアプリケーションに問題を引き起こすかどうかを判断します。最も重要なことは、「ユーザーは実際に不満を抱いているのか?」という重要な質問を自分自身に問いかけることです。

7. 手書きオブジェクト プールは、大規模なクラスのアプリケーションに適しています

Stop-The-World の一時停止がある程度悪いものであることを考慮すると、アプリケーション開発チームの一般的な反応は、Java ヒープ内に独自のメモリ管理テクノロジを実装することです。これは多くの場合、オブジェクト プール (または完全な参照カウント) を実装し、ドメイン オブジェクトを使用するコードを関与させる必要があるということになります。

このテクニックは、ほとんどの場合、誤解を招きます。これは、オブジェクトの割り当てに非常にコストがかかり、オブジェクトの変更がはるかに安価だった過去の理解に基づいています。今では状況はまったく異なります。

現在のハードウェアは割り当てにおいて非常に効率的であり、最新のデスクトップまたはサーバー ハードウェアでは、メモリ帯域幅は少なくとも 2 ~ 3 GB です。これは大きな数であり、アプリケーションが特別に作成されない限り、このような広い帯域幅を最大限に活用するのは簡単ではありません。

一般に、オブジェクト プーリングを正しく実装することは非常に難しく (特に複数のスレッドが動作している場合)、オブジェクト プーリングにはいくつかのマイナス要件もあり、この手法が一般的に良い選択とは言えません。オブジェクト プールのコードはオブジェクト プールを理解し、それを正しく処理できなければなりません

どのコードがオブジェクト プールを認識し、どのコードがオブジェクト プールを認識していないか?境界は誰もが知っており、ドキュメントに記述されている必要があります

これら追加の複雑さ 常に更新し、定期的にレビューしてください

そのうちの 1 つが満たされていない場合、問題が静かに発生するリスク (C でのポインターの再利用と同様) が再発します

つまり、受け入れられないのは GC の一時停止だけであり、調整と再構築が必要です。 オブジェクト プーリングは、ストールを許容レベルまで低減できない場合にのみ使用できます。

8. ガベージ コレクションでは、Parallel Old よりも CMS が常に優れた選択肢です。

Oracle JDK は、デフォルトで、古い世代を収集するために並列 Stop-The-World コレクター、つまり Parallel Old コレクターを使用します。

Concurrent-Mark-Sweet (CMS) は、ほとんどのガベージ コレクション サイクル中にアプリケーション スレッドが実行を継続できるようにする代替手段ですが、コストがかかり、いくつかの注意点があります。

アプリケーション スレッドをガベージ コレクション スレッドと一緒に実行できるようにすると、必然的に問題が発生します。アプリケーション スレッドがオブジェクト グラフを変更し、オブジェクトの実行可能性に影響を与える可能性があります。この状況は事後に解決する必要があるため、CMS には実際には 2 つの STW フェーズ (通常は非常に短い) があります。

これにはいくつかの影響があります。

すべてのアプリケーション スレッドは安全なポイントに移動する必要があり、各 Full GC 中に 2 回一時停止されます。

ガベージ コレクションはアプリケーションと同時に実行されますが、アプリケーションのスループットは低下します。削減 (通常は 50%);

ガベージ コレクションに CMS を使用する場合、JVM によって使用されるブックキーピング情報 (および CPU サイクル) は他の並列コレクターよりもはるかに多くなります。

これらのコストがお金に見合う価値があるかどうかは、アプリケーションによって異なります。しかし、無料のランチはありません。 CMS コレクターの設計は賞賛に値しますが、万能薬ではありません。

したがって、CMS が正しいガベージ コレクション戦略であることを確認する前に、まず、Parallel Old の STW 一時停止が実際には受け入れられず、調整できないことを確認する必要があります。最後に、すべてのメトリクスは運用システムと同等のシステムから取得する必要があることを強調します。

9. ヒープ サイズを増やすことでメモリの問題を解決できる可能性があります

アプリケーションに問題が発生し、GC の問題が疑われる場合、多くのアプリケーション チームの反応はヒープ サイズを増やすことです。場合によっては、これによりすぐに結果が得られ、より思慮深い解決策を検討する時間を得ることができます。ただし、パフォーマンスの問題の原因が完全に理解されていない場合、この戦略は状況を悪化させる可能性があります。

大量のドメイン オブジェクト (その存続期間は代表的なもので、たとえば 2 ~ 3 秒) を生成する、非常に不十分にコーディングされたアプリケーションを考えてみましょう。割り当て率が十分に高い場合、ガベージ コレクションが頻繁に発生するため、ドメイン オブジェクトは古い世代に昇格されます。ドメイン オブジェクトが古い世代に入るとほぼすぐに、その生存期間は終了し、直接消滅しますが、次のフル GC までリサイクルされません。

アプリケーションのヒープ サイズを増やすと、比較的寿命の短いオブジェクトが入ったり消えたりするために使用されるスペースが増えるだけです。これにより、Stop-The-World の一時停止時間が長くなり、アプリケーションにとっては有益ではありません。

ヒープ サイズを変更したり、他のパラメーターを調整したりする前に、オブジェクトの割り当てと有効期間のダイナミクスを理解する必要があります。パフォーマンス データを測定せずにやみくもに行動すると、状況はさらに悪化するだけです。ここでは、ガベージ コレクターの古い世代のディストリビューションが特に重要です。

結論

Java のパフォーマンス チューニングに関しては、直感が誤解を招くことがよくあります。プラットフォームの動作を視覚化し、理解を高めるには、実験データとツールが必要です。

ガベージ コレクションがその最良の例です。チューニングやチューニングをガイドするデータの生成では、GC サブシステムには無限の可能性がありますが、実稼働アプリケーションでは、ツールを使用せずに生成されたデータの意味を理解するのは困難です。

デフォルトでは、Java プロセス (開発環境と運用環境を含む) を実行するときは、常に少なくとも次のパラメータを使用する必要があります:

-verbose:gc (GC ログを出力)
-Xloggc: (より包括的な GC ログ)
-XX:+PrintGCDetails (より詳細な出力)
-XX:+PrintTenuringDistribution (オブジェクトを古い世代に昇格させるために JVM によって使用される経過時間のしきい値を表示します)

次に、ツールを使用してログを分析します。ここでは手書きのスクリプトを使用できます。グラフを生成するには、GCViewer (オープン ソース) や jClarity Censum などの視覚化ツールを使用することもできます。


このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Javaの完全数 Javaの完全数 Aug 30, 2024 pm 04:28 PM

Java における完全数のガイド。ここでは、定義、Java で完全数を確認する方法、コード実装の例について説明します。

ジャワのウェカ ジャワのウェカ Aug 30, 2024 pm 04:28 PM

Java の Weka へのガイド。ここでは、weka java の概要、使い方、プラットフォームの種類、利点について例を交えて説明します。

Javaのスミス番号 Javaのスミス番号 Aug 30, 2024 pm 04:28 PM

Java のスミス番号のガイド。ここでは定義、Java でスミス番号を確認する方法について説明します。コード実装の例。

Java Springのインタビューの質問 Java Springのインタビューの質問 Aug 30, 2024 pm 04:29 PM

この記事では、Java Spring の面接で最もよく聞かれる質問とその詳細な回答をまとめました。面接を突破できるように。

Java 8 Stream Foreachから休憩または戻ってきますか? Java 8 Stream Foreachから休憩または戻ってきますか? Feb 07, 2025 pm 12:09 PM

Java 8は、Stream APIを導入し、データ収集を処理する強力で表現力のある方法を提供します。ただし、ストリームを使用する際の一般的な質問は次のとおりです。 従来のループにより、早期の中断やリターンが可能になりますが、StreamのForeachメソッドはこの方法を直接サポートしていません。この記事では、理由を説明し、ストリーム処理システムに早期終了を実装するための代替方法を調査します。 さらに読み取り:JavaストリームAPIの改善 ストリームを理解してください Foreachメソッドは、ストリーム内の各要素で1つの操作を実行する端末操作です。その設計意図はです

Java での日付までのタイムスタンプ Java での日付までのタイムスタンプ Aug 30, 2024 pm 04:28 PM

Java での日付までのタイムスタンプに関するガイド。ここでは、Java でタイムスタンプを日付に変換する方法とその概要について、例とともに説明します。

カプセルの量を見つけるためのJavaプログラム カプセルの量を見つけるためのJavaプログラム Feb 07, 2025 am 11:37 AM

カプセルは3次元の幾何学的図形で、両端にシリンダーと半球で構成されています。カプセルの体積は、シリンダーの体積と両端に半球の体積を追加することで計算できます。このチュートリアルでは、さまざまな方法を使用して、Javaの特定のカプセルの体積を計算する方法について説明します。 カプセルボリュームフォーミュラ カプセルボリュームの式は次のとおりです。 カプセル体積=円筒形の体積2つの半球体積 で、 R:半球の半径。 H:シリンダーの高さ(半球を除く)。 例1 入力 RADIUS = 5ユニット 高さ= 10単位 出力 ボリューム= 1570.8立方ユニット 説明する 式を使用してボリュームを計算します。 ボリューム=π×R2×H(4

未来を創る: まったくの初心者のための Java プログラミング 未来を創る: まったくの初心者のための Java プログラミング Oct 13, 2024 pm 01:32 PM

Java は、初心者と経験豊富な開発者の両方が学習できる人気のあるプログラミング言語です。このチュートリアルは基本的な概念から始まり、高度なトピックに進みます。 Java Development Kit をインストールしたら、簡単な「Hello, World!」プログラムを作成してプログラミングを練習できます。コードを理解したら、コマンド プロンプトを使用してプログラムをコンパイルして実行すると、コンソールに「Hello, World!」と出力されます。 Java の学習はプログラミングの旅の始まりであり、習熟が深まるにつれて、より複雑なアプリケーションを作成できるようになります。

See all articles