Javaプログラムパフォーマンスの基本的なポジショニング分析

1.背景

パフォーマンステストでは、Javaアプリケーション、パフォーマンスの観察方法、メソッドを介したコードの検索方法、一般的な手順があるかどうかを常に考え、資料を調べて前任者の知識の要約を参照することで、次のことがわかります。知っているということは「はい」という意味ではないという記事は、「はい」を使用できることと同等であり、継続的な意識的な実践によってのみ習得することができます。要するに、これは基本的なスキルです。この基礎があれば、高度なツール(Ali's Arthasなど)を使用でき、スムーズな航海が可能になります。

今回は、Jmeterパフォーマンスストレステストプラットフォームを対象としています。このプラットフォームの紹介は、https ://smooth.blog.csdn.net/article/details/83380879で確認できます。JAVAプロセスの占有率を高めるためにCPU、実行するプラットフォームをテストするように圧力をかけます(スクリプトをバックグラウンドで実行させるだけです)。

2.Linuxでのポジショニング

2.1操作手順

  • TOPコマンドを使用して、高いCPUプロセスを消費しているユーザーを特定します(例:pid = 1234)。
  • top -p 1234を使用して、プロセスのみを監視します
  • 大文字のHを入力して、現在のプロセスのすべてのスレッドを一覧表示します
  • CPU消費量の多いスレッドを確認し、131420などのスレッド番号を確認してください
  • jstack 1234> pagainfo.dumpを使用して、現在のプロセスでのダンプスレッド情報を取得します(jstackにはJDKが付属しています)
  • 4番目のステップで取得したスレッド番号131420を16進数の2015cに変換します(printf "%x \ n" 131420)
  • 2015cに従って、ステップ5で取得したスタック情報でnid=0x2015cのスレッドを見つけます。
  • コードの場所を特定します(印刷されたスタック情報に基づいてコードの場所を確認します)

注:オペレーティングシステムによって出力された仮想マシンのローカルスレッドから、ローカルスレッドの数はJavaスレッドスタックのスレッドの数と同じであり、2つが1対1で対応していることを示しています。Javaスレッドのnidは16進数で表され、ローカルスレッドのidは10進数で表されるだけです。

2.2デモンストレーション

1.最初にTOPコマンドを使用して、CPU使用率が高いプロセスを見つけます。もちろんそれはJAVAです(デモンストレーションのためだけに、高くはなく、他のプロセスと比較して比較的高いです)

 2. top -p 29866 Hを使用して、プロセスのすべてのスレッドを監視します

監視オブジェクトとして最初のスレッド70603を選択しました(当面、CPUが最も高いスレッドは見つからなかったため、比較的高いスレッドを選択できます)。

3.手順2で取得したスレッド番号70603を16進数の113cbに変換します printf "%x \ n" 70603)

[root@localhost local]# printf "%x\n" 70603
113cb

4.最初にjstack29866>/opt/smooth/test.dumpを使用して、現在のプロセスでのダンプスレッド情報を取得します

viまたはvimコマンドでtest.dumpファイルを開き、次のように113cbを見つけます。

最初の行の「main」はスレッド名です。tidはJavaスレッドIDを参照します。nidは、ネイティブスレッドのIDを指します。prioはスレッドの優先順位です。[0x00007f1064064000]は、スレッドスタックの開始アドレスです。

       上記から、現在のスレッドがTIMED_WAITING状態にあり、現在条件付きで中断されていることがわかります。パフォーマンスストレステストプラットフォームの特性によると、これはストレステストであり、ストレステストスレッドを待機しています。停止するには:waitThreadstopped、赤い部分を見つけます。セクションでマークされたボックス内のクラスとメソッドは、以下に示すように、クラスファイルLocalStandardJMeterEngineで540行目のコードを見つけます。

次に、赤いボックスでマークされた次の行で示されているコードの468行目を見つけます。

この時点で、探している関数をトレースしました(もちろん、スローコード行をトレースする必要があります。システムのソースコードと構造をある程度理解していることが前提です。そうしないと、より手間がかかります。痕跡)。

3.Windowsでのポジショニング

3.1操作手順

  • タスクマネージャーを使用して([ビュー]-> [選択]列でPIDを確認する必要があります)、pid=1234などの高いCPUを占有するプロセスを表示します。
  • pslist -dmx 1234コマンドを使用します( Microsoftの公式Webサイトからhttp://technet.microsoft.com/en-us/sysinternals/bb896682.aspxをダウンロードする必要があります 。解凍後、pslist.exeをC:\ Windows\System32にコピーします。 )プロセスのすべてのスレッドを監視する
  • 時間のかかるスレッドを確認し、131420などのスレッド番号を確認してください
  • cmdにJDKbinディレクトリを入力し、jstack 1234> pagainfo.dumpを使用して、現在のプロセスでのダンプスレッド情報を取得します。
  • 3番目のステップで取得したスレッド番号131420を16進数の2015cに変換します(変換が面倒な場合は、インターネット上のオンライン16進数変換ツールを使用できます)
  • 2015cに従ってステップ4で取得したスタック情報でnid=0x2015cのスレッドを見つけます
  • コードの場所を特定します(印刷されたスタック情報に基づいてコードの場所を確認します)

説明:Windowsではトップコマンドがないことを除いて、基本的にWindowsとLinuxのポジショニング手順に違いはありませんが、より直感的なタスクマネージャーがあります。タスクマネージャーはスレッドを監視できないため、別のツールPSToolが使用されます。

3.2デモンストレーション

1.タスクマネージャーを開き(選択列のPIDとコマンドラインの両方をチェックします)、JAVAプロセスを見つけ、コマンドラインをチェックして、監視するアプリケーションを決定します。

2.タスクマネージャーで対応するPID4564を見つけ、コマンドpslist-dmx4564を使用してすべてのスレッドを表示します。

       Cswtch(コンテキスト切り替え)とユーザー時間が比較的高いスレッドが見つかりました(リソース消費量の多いすべてのスレッドが監視するオブジェクトに属しているわけではありません。結論を出す前に、ダンプファイルの内容を比較して表示する必要があります)。

3.オンラインの16進変換ツールをオンラインで見つけて、Tid=7612を変換します。

 4. JDKのbinディレクトリに入り、jstack 7612> test.dumpコマンドを実行し、ダンプファイルを生成し、エディタで開いて、1dbcを見つけます。

       スレッドが一時停止状態にあり(<0x0000000083e72c18>がウェイクアップするのを待つ別の条件を待機している)、BackendListenerはjmeterエンジンに付属するクラスに属しており、今回は焦点を当てていません(今回はパフ​​ォーマンスストレステストプラットフォームに焦点を当てます。クラスとメソッド)。

5.別のスレッドを変更して表示し、ユーザー時間が比較的長い別のスレッドを選択します。Tid= 8120:

6.変換プロセスの後、ダンプファイルに移動し、1fb8を検索して、次のスレッドのスタック情報を見つけます。

このスタックはどれほど馴染みがあり、Linuxの下にあるLocalStandardJMeterEngineクラスと同じです。現在のスレッドも条件付きで中断され、ソースコードクラスを開き、コードの523行目を見つけます。同じです。

同じ結果の467行目のコードを見つけます。 

       これは、Windowsでは、Linuxと同じJAVAプロセススレッド追跡を実行できることを意味します(もちろん、Javaプログラムは通常Linuxで展開されます)。

4.まとめ

       上記は単なる例です。実際、上記のプロセスはパフォーマンステストではなく、パフォーマンスのボトルネックの問題がないため、実際の分析はこれよりもはるかに困難です。これは単純なJavaプロセス、スレッド、およびコードの追跡です。 。言い換えれば、知ることは知ることを意味するのではなく、知ることはそれを使用できることを意味するのではなく、意識的に実践することによってのみそれを習得することができます。

       さらに、スレッドのステータスについては、それを理解できる必要があります。理解した場合にのみ、分析に役立ちます。

        1 >>実行可能:スレッドは実行中であり、要求/計算/ファイル操作の処理などのリソースを占有しています。

        2 >> BLOCKED /ロックを待っています  (焦点を合わせる必要があります)

            >>>ブロックされたスレッドはブロックされた状態にあり、特定のリソースを待機しています(これは、リソースのタイムアウトを待機しているスレッドとして理解できます)。

            >>>「ロックを待機中」、つまりxxxをロックするのを待機し、スタックファイルをgrepしてロックを検索し、ロックを取得したスレッドを検索します。

            >>>「モニターエントリを待機中」スレッドはsynchronized(obj){...}アプリケーションを介してクリティカルセクションに入りますが、objに対応するモニターは他のスレッドによって所有されているため、待機中です。

        3 >> WAITING / TIMED_WAITING {TIMED}  (フォロー)

            >>> "TIMED_WAITING(parking)":待機状態、および指定された時間は、指定された時間に達した後、自動的に待機状態を終了します。パーキングは、スレッドが一時停止されていることを意味します。

            >>>「条件付きで待機中」は、スタック内の「待機するためのパーキング(java.util.concurrent.SynchronousQueue $ TransferStack)」と組み合わせる必要があります。最初->このスレッドは特定の条件の発生を待って自動的にウェイクアップします。2番目->SynchronousQueueはキューではなく、要素をSynchronousQueueに配置するときに、スレッド間で情報を転送するためのメカニズムです。ハンドオーバーの受け入れを待機している別のスレッドであるため、これがこのスレッドが待機している条件です。

        4 >>デッドロック(特別な注意が必要):デッドロック、リソースは互いに占有します。

        その他の指示:

  • スレッドの説明は「モニターエントリを待機中」です

        クリティカルセクションに入るのを待っているので、「エントリセット」キューで待っていることを意味します。

        この時点で、スレッドの状態は通常ブロックされています。

        java.lang.Thread.State:BLOCKED(オブジェクトモニター上)      

  •  スレッドの説明は「条件付きで待機中」です

        これは、別の条件が発生するのを待って自分自身をウェイクアップするか、単にsleep(N)を呼び出すことを意味します。

        このとき、スレッドの状態はおおまかに次のようになります。

        java.lang.Thread.State:WAITING(パーキング):その状態が発生するのを待ち続けます。

        java.lang.Thread.State:TIMED_WAITING(パーキングまたはスリープ):タイミングが設定されています。条件が満たされない場合は、定期的にウェイクアップします。  

  •  多数のスレッドが「モニターのエントリーを待機している」場合

        グローバルロックが多数のスレッドをブロックしている可能性があります。

        短時間で印刷されたスレッドダンプファイルが、時間の経過とともにモニターエントリを待機するスレッドが増え、減少傾向がないことを反映している場合は、一部のスレッドがクリティカルセクションに長時間留まっていることを意味している可能性があります、したがって、ますます多くの新しいスレッドに関しては、クリティカルセクションに入るのが遅いです。

  •  多数のスレッドが「条件付きで待機」している場合

        サードパーティのリソース、特にサードパーティのネットワークリソースを取得するために実行され、長時間応答を取得できなかったために、多数のスレッドが待機状態になっている可能性があります。

        したがって、多数のスレッドが待機状態にあり、スレッドスタックから、ネットワークの読み取りと書き込みを待機していることがわかった場合、これはネットワークのボトルネックの兆候である可能性があります。実行中。

        スレッドの状態は「Object.wait()内」です。

        モニターを取得したことを示した後、java.lang.Object.wait()メソッドを呼び出します。

        各モニターは、特定の時間に1つのスレッド(「アクティブスレッド」)のみが所有できますが、他のスレッドは「待機スレッド」であり、それぞれ「エントリセット」と「待機セット」の2つのキューで待機します。「EntrySet」で待機しているスレッド状態は「Waitingformonitorentry」であり、「WaitSet」で待機しているスレッド状態は「inObject.wait()」です。

        スレッドがモニターを取得すると、スレッドが実行を継続するための条件が満たされていないことが判明した場合、スレッドはオブジェクト(通常は同期されたオブジェクト)のwait()メソッドを呼び出し、モニターを放棄して、「待機セット」に入ります。 " 列。

        このとき、スレッドの状態はおおまかに次のようになります。

        java.lang.Thread.State:TIMED_WAITING(オブジェクトモニター上);

        java.lang.Thread.State:WAITING(オブジェクトモニター上);

        通常、RMI関連のスレッド(RMI RenewClean、GC Daemon、RMI Reaper)、GCスレッド(Finalizer)、参照オブジェクトのガベージコレクションスレッド(Reference Handler)などのシステムスレッドはこの状態です。

おすすめ

転載: blog.csdn.net/smooth00/article/details/106467802