この記事は「Java パフォーマンス」からの抜粋です。Java のパフォーマンスに関心がある学生はおそらくこの本を知っているでしょう。多くの学生が日常的に Java コードを書くときにパフォーマンスについて気にすることはほとんどないかもしれません。実際、プロセスは、算術演算を実装するためのビット演算の使用から、JAVA コードの全体的なアーキテクチャ設計まで、プログラムのパフォーマンスへの影響と切り離すことはできません。この記事では、主にパフォーマンスの分野で私たちがより懸念しているいくつかの問題についていくつかの点について説明します。学生がパフォーマンスに興味がある場合は、それぞれの点を一緒に詳しく学ぶことができます。
パフォーマンス チューニングには通常 3 つのステップがあります: 1. パフォーマンスの監視、2. パフォーマンスの分析、3. パフォーマンスのチューニング
オペレーティング システムのパフォーマンスの主な焦点は次の点です: CPU 使用率、CPU スケジューリング実行キュー、メモリ使用率、ネットワーク I/O、ディスク I/O。
1.CPU 使用率
アプリケーションが最高のパフォーマンスとスケーラビリティを達成するには、CPU サイクルの利用可能な部分を最大限に活用するだけでなく、CPU サイクルのこの部分も活用する必要があります。 CPU は無駄ではなく、より効率的になります。マルチプロセッサおよびマルチコア システム上で実行されるマルチスレッド アプリケーションにとって、CPU サイクルを最大限に活用することは非常に困難です。また、CPU が飽和状態に達しても、CPU のパフォーマンスとスケーラビリティが最適な状態に達したことを意味するわけではありません。アプリケーションが CPU リソースをどのように利用しているかを区別するには、それをオペレーティング システム レベルで検出する必要があります。多くのオペレーティング システムでは、CPU 使用率統計レポートには通常、ユーザーとシステム、またはオペレーティング システムのカーネル使用率が含まれます。ユーザーの CPU 使用量は、アプリケーションがアプリケーション コードの実行に使用する時間です。対照的に、カーネルおよびシステムの CPU 使用率は、アプリケーションがオペレーティング システムのカーネル コード ロックの実行に費やした時間を指します。カーネルまたはシステムの CPU 使用率が高い場合は、共有リソースの圧迫または大量の I/O デバイスの対話を示している可能性があります。アプリケーションのパフォーマンスとスケーラビリティを向上させるには、カーネルまたはシステム コードの実行に費やされる時間をアプリケーション コードの実行に使用できるため、カーネルまたはシステムの CPU 時間を 0% にするのが理想的な状態です。したがって、CPU 使用率の最適化の正しい方向は、CPU がカーネル コードまたはシステム コードの実行に費やす時間をできるだけ減らすことです。
コンピューティング集約型アプリケーションの場合、パフォーマンス監視は、ユーザーの CPU 使用率やカーネルまたはシステムの CPU 使用率の監視よりも詳細であり、CPU クロック サイクル (クロックあたりの命令数、IPC) 内の実行数を監視する必要があります。または、各 CPU 実行で使用される CPU サイクル (命令あたりのサイクル数、CPI)。コンピューティング集約型のアプリケーションの場合、これら 2 つの側面から CPU を監視することは良い選択です。これは、最新のオペレーティング システムのパッケージ化された CPU パフォーマンス レポート ツールは通常、CPU サイクル中の CPU 使用率ではなく、CPU 使用率のみを出力するためです。命令を実行します。これは、CPU がメモリ内でデータを待機しているときに、オペレーティング システムの CPU パフォーマンス レポート ツールもこのシナリオを「ストール」と呼びます。「ストール」シナリオは、次のような場合によく発生します。 CPU 命令が実行されるときは常に、命令に必要なデータの準備ができていない限り、つまりデータがレジスタまたは CPU キャッシュにない限り、「ストール」シナリオが発生します。
「ストール」シナリオが発生すると、CPU は命令に必要なデータがレジスタまたはバッファに到着するまで待機する必要があるため、クロック サイクルを無駄にします。このシナリオでは、数百の CPU クロック サイクルが無駄になるのが通常です。したがって、コンピューティング集約型のアプリケーションでは、パフォーマンスを向上させる戦略は、「ストール」シナリオの発生を減らすか、CPU キャッシュの使用を強化することです。データを待機して無駄になる CPU サイクルがより少なくなります。この種のパフォーマンス監視に関する知識は本書の内容を超えているため、パフォーマンスの専門家の助けが必要です。ただし、後述する Oracle Solaris Studio Performance Analyzer などのパフォーマンス分析ツールには、そのようなデータが含まれます。
2.CPUスケジューリングキュー
CPU 使用率の監視に加えて、CPU 実行キューを監視することでシステムが完全に負荷されているかどうかを確認することもできます。実行キューは、軽量プロセスを格納するために使用されます。これらのプロセスは、通常は実行可能ですが、CPU スケジューリングを待機しており、現在のプロセッサーが処理できる軽量プロセスの数が増加したときに、スケジューリング キュー内で待機状態になります。多数あると、スケジューリング キューが生成されます。 CPU ディスパッチ キューが深い場合は、システムが完全にロードされていることを示します。システムの実行キューの深さは、仮想プロセッサによって実行できない待機数に等しく、仮想プロセッサの数はシステム内のハードウェア スレッドの数に等しくなります。 Java の API、Runtime.avaliableProcessors() を使用して仮想プロセッサの数を取得できます。実行キューの深さが仮想プロセッサの数の 4 倍以上になると、オペレーティング システムが応答しなくなります。
CPU スケジューリング キューを検出するための一般的なガイドラインは、キューの深さが仮想プロセスの数の 2 倍を超えていることが判明した場合に注意を払うことですが、すぐにアクションを起こす必要はありません。 3 倍を超える場合、または 4 倍以上の場合は、注意して遅滞なく問題を解決する必要があります。
通常、キューの深さを観察するには 2 つのオプションの方法があります。1 つは、CPU を追加するか、既存の CPU の負荷を軽減することによって負荷を共有することです。このアプローチでは基本的に、実行ユニットあたりのロード スレッドの数が減り、それによって実行キューの深さが減ります。
もう 1 つの方法は、システム上で実行されているアプリケーションをプロファイリングすることにより、CPU 使用率を増やすことです。言い換えれば、ガベージ コレクションに費やされる CPU サイクルを削減する方法を見つけるか、CPU 命令の実行に使用する CPU サイクルを減らすためのより良いアルゴリズムを見つけることです。パフォーマンスの専門家は通常、後者のアプローチ、つまりコード実行パスの長さを削減し、より適切な CPU 命令を選択することに重点を置いています。 JAVA プログラマーは、実行アルゴリズムとデータ構造を改善することで、コードの実行効率を向上させることができます。
3. メモリ使用率
CPU 使用率に加えて、システムのメモリ属性も監視する必要があります。これらの属性には、たとえば、ページング、スワップ、ロック、マルチスレッドによるコンテキストの切り替えなどが含まれます。
スワップは通常、アプリケーションが必要とするメモリが実際の物理メモリよりも大きい場合に発生します。この状況に対処するために、オペレーティング システムは通常、スワップ領域と呼ばれる対応する領域を構成します。通常、スワップ領域は物理ディスク上にあり、アプリケーションが物理メモリを使い果たすと、オペレーティング システムはメモリ データの一部を一時的にディスク領域にスワップします。アクセス頻度は比較に影響を与えません。ディスク領域にスワップされたメモリがアプリケーションによってアクセスされる場合、スワップはパフォーマンスに影響します。アプリケーションの。
仮想マシンのガベージ コレクターのパフォーマンスは、スワップ中に非常に低下します。これは、ガベージ コレクターが訪問する領域のほとんどが到達不能であるためです。つまり、ガベージ コレクターによってスワップ アクティビティが発生することになります。このシーンは劇的です。ガベージ コレクションされたヒープ領域がディスク領域にスワップされた場合、このときスワップがページ単位で発生するため、スワップ プロセス中にガベージ コレクタによってスキャンされる可能性があり、ガベージが大幅に発生します。このとき、ガベージコレクタが「Stop The World」(アプリケーションの応答を停止させる)の場合、コレクタの収集時間が延長されます。
4. ネットワーク I/O
分散型 JAVA アプリケーションのパフォーマンスとスケーラビリティは、ネットワーク帯域幅とネットワーク パフォーマンスによって制限されます。たとえば、処理できる量を超えるパケットをネットワーク インターフェイスに送信すると、パケットがオペレーティング システムのバッファに蓄積され、アプリケーションの遅延が発生するほか、他の状況でもネットワーク アプリケーションの遅延が発生します。
差別化と監視のためのツールは、多くの場合、オペレーティング システムのパッケージ化ツールでは見つけるのが困難です。 Linux には netstat コマンドが用意されていますが、Linux と Solaris は両方ともネットワーク使用量の実装を提供し、パケットの送信、受信、エラー パケット、競合、その他の情報を 1 秒ごとに提供します。イーサネットでは、少数のパケット衝突が発生するのが通常です。パケットエラーが多い場合は、ネットワークカードに問題がある可能性があります。同時に、netstat はネットワーク インターフェイスの送受信データをカウントできますが、ネットワーク カードが完全に利用されているかどうかを判断することは困難です。たとえば、netstat -i でネットワーク カードから 1 秒あたり 2500 パケットが送信されていることを示しても、現在のネットワーク使用率が 100% であるか 1% であるかを判断できない場合、現在トラフィックがあることしかわかりません。これは、ネットワーク パケット サイズが分からない場合に到達できる結論にすぎません。簡単に言えば、Linux および Solaris が提供する netstat を使用して、現在のネットワークがパフォーマンスに影響を与えるかどうかを判断することはできません。 JAVA アプリケーションの実行中にネットワークを監視するには、他のツールが必要です。
5. ディスク I/O
アプリケーションがディスク上で動作する場合、考えられるディスク パフォーマンスの問題を監視するためにディスクを監視する必要があります。データベースなど、一部のアプリケーションは I/O 集中型です。通常、アプリケーション ログ システムでもディスクが使用され、システム動作中に重要な情報を記録するために使用されます。