jdkのjps、jstackツールを使用してコードの問題を検出し、プログラムの性能を高める



今日はjdkのjpsとjstackツールを組み合わせた位置決めコードの問題をどのように利用し、プログラムの安定性、丈夫性、性能を高めるかを共有します.
jdkのbinでは、ディレクトリの下に図のようなツールがたくさんあります.
jps、jstackツールの紹介:
jps:
JDK 1です.5現在のすべてのjavaプロセスpidを表示するコマンドを提供します.簡単で実用的で、linux/unixプラットフォームで現在のjavaプロセスの簡単な状況を簡単に見るのに適しています.
コマンドフォーマット:jps[options][hostid]
[options]オプション:
-q:VM識別子のみを出力します.classname,jar name,arguments in main methodは含まれません.
-m:main methodのパラメータを出力
-l:完全なパッケージ名を出力し、メインクラス名を適用し、jarの完全なパス名を出力します.
-v:jvmパラメータの出力
-V:flagファイルを介してJVMに渡されるパラメータ(.hotspotrcファイルまたは-XX:Flags=指定ファイル)を出力します.
-Joption:vmにパラメータを渡します.例:-J-Xms 1024 m
例として-lを使用します.
図では、第1の例はプロセス番号であり、第2の例はactivemq(/home/activeMq/apache-activemq-5.5.1/bin/run.jar)、dubboなどのプロセス名(実行されるプログラム)である.
サービス(com.alibaba.dubbo.container.Main)、tomcat(org.apache.catalina.startup.Bootstrap)など.
jstack:
jstackはjava仮想マシンに付属するスタックトラッキングツールです.jstackはjava仮想マシンの現在の時刻のスレッドスナップショットを生成するために使用されます.スレッドスナップショットは、現在のjava仮想マシン内の各スレッド正です.
実行されるメソッドスタックのセットで、スレッドスナップショットを生成する主な目的は、スレッド間のデッドロック、デッドサイクル、外部リソースの要求による長時間の停止の原因を特定することです.
待ち時間など.
スレッドが停止したときにjstackで各スレッドの呼び出しスタックを表示すると、応答のないスレッドがバックグラウンドで何をしているのか、リソースを待っているのかがわかります.
コマンドフォーマット:jstack[option]pid
[options]オプション:
-F:「jstack[-l]pid」が応答しない場合、スタック情報を強制的に印刷する.
-l:長いリスト.ロックに関する追加情報を印刷する、例えばjavaに属する.util.concurrentのownable synchronizersリスト.
-m:javaとnative c/c++フレームワークのすべてのスタック情報を印刷します.-h|-help印刷ヘルプ情報
pid:印刷される構成情報が必要なjavaプロセスidはjpsツールでクエリーできます
例として-lを使用します.
コマンド:
実行結果:
図から、各スレッドの呼び出しスタックを表示すると、応答のないスレッドがバックグラウンドで何をしているのか、リソースを待っているのかを知ることができます.
jps、jstack検索コードの問題
原理:
jpsコマンドで対応するプログラムのプロセスを検索し、プロセス番号を記録し、jstackコマンドでそのプロセス番号が存在するプログラムのスレッドスタック情報をファイルに出力し、ファイル内の情報を行う
分析し、原因を見つけ、問題を解決します.
注意:この方法はできるだけ同時に使用すると、コードの問題を見つけやすくなります.
手順:
1).図のようにjdkのbinディレクトリに入ります.
2).jpsツールを使用してtomcatのプロセスを表示します(linux環境であればpsコマンドを推奨します).
tomcatが1つしかインストールされていないので、jps-mコマンドを使用します(複数のtomcatがインストールされている場合は、jps-vコマンドを使用します.このコマンドの実行結果には、各tomcatのパスが表示されます).
3).jstackコマンドを実行し、出力結果をログファイルに出力します.
コマンド:
[root@s4 bin]# jstack 28501 >log1.log

ファイルlog 1を開く.ロゴファイルは中身を見てください.
[root@s4 bin]# tail -200f log1.log
        - locked <0x00000007058fc4b0> (a org.apache.tomcat.util.net.JIoEndpoint$Worker)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:484)
        at java.lang.Thread.run(Thread.java:662)

"http-8090-11" daemon prio=10 tid=0x00002aaab4047000 nid=0x7181 in Object.wait() [0x000000004238b000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x00000007056433f0> (a org.apache.tomcat.util.net.JIoEndpoint$Worker)
        at java.lang.Object.wait(Object.java:485)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.await(JIoEndpoint.java:458)
        - locked <0x00000007056433f0> (a org.apache.tomcat.util.net.JIoEndpoint$Worker)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:484)
        at java.lang.Thread.run(Thread.java:662)

"http-8090-10" daemon prio=10 tid=0x00002aaab46ec000 nid=0x7180 in Object.wait() [0x000000004228a000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x0000000705643610> (a org.apache.tomcat.util.net.JIoEndpoint$Worker)
        at java.lang.Object.wait(Object.java:485)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.await(JIoEndpoint.java:458)
        - locked <0x0000000705643610> (a org.apache.tomcat.util.net.JIoEndpoint$Worker)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:484)
        at java.lang.Thread.run(Thread.java:662)

"http-8090-9" daemon prio=10 tid=0x00002aaab4525800 nid=0x717f in Object.wait() [0x000000004078a000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x0000000705643898> (a org.apache.tomcat.util.net.JIoEndpoint$Worker)
        at java.lang.Object.wait(Object.java:485)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.await(JIoEndpoint.java:458)
        - locked <0x0000000705643898> (a org.apache.tomcat.util.net.JIoEndpoint$Worker)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:484)
        at java.lang.Thread.run(Thread.java:662)

4).ログ・ファイルの分析
上のtomcatは圧力テストを行っていないので、tomcatのスレッドには自分のプログラムコードのないスレッドが見えます.そのため、この間の入力を使用します.
圧力テスト後にエクスポートされたログを分析します.一部のログの内容は次のとおりです.
"DubboClientHandler-192.168.6.162:2099-thread-2" daemon prio=10 tid=0x00002aaac069a000 nid=0x14c1 waiting on condition [0x000000004867f000]
   java.lang.Thread.State: TIMED_WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0x0000000782c4d8e0> (a java.util.concurrent.SynchronousQueue$TransferStack)
	at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:198)
	at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:424)
	at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:323)
	at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:874)
	at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:945)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
	at java.lang.Thread.run(Thread.java:662)

"DubboClientHandler-192.168.6.162:2099-thread-2" daemon prio=10 tid=0x000000005be86000 nid=0x14c0 waiting on condition [0x000000004863e000]
   java.lang.Thread.State: TIMED_WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0x0000000782c61ac0> (a java.util.concurrent.SynchronousQueue$TransferStack)
	at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:198)
	at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:424)
	at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:323)
	at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:874)
	at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:945)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
	at java.lang.Thread.run(Thread.java:662)


"http-portal%2F192.168.6.162-8097-184" daemon prio=10 tid=0x00002aaab0ecc800 nid=0x2d7a waiting for monitor entry [0x0000000045fa9000]  
  java.lang.Thread.State: BLOCKED (on object monitor)  
    at org.apache.log4j.Category.callAppenders(Category.java:204)  
    - waiting to lock <0x00000007800020a0> (a org.apache.log4j.spi.RootLogger)  
    at org.apache.log4j.Category.forcedLog(Category.java:391)  
    at org.apache.log4j.Category.log(Category.java:856)  
    at org.slf4j.impl.Log4jLoggerAdapter.info(Log4jLoggerAdapter.java:304)  

最後のログからこのログスレッドがBLOCKED状態でorgに入ることがわかる.apache.log4j.CategoryクラスのcallAppendersメソッド、
コードは次のとおりです.
/**
     Call the appenders in the hierrachy starting at
     <code>this</code>.  If no appenders could be found, emit a
     warning.

     <p>This method calls all the appenders inherited from the
     hierarchy circumventing any evaluation of whether to log or not
     to log the particular log request.

     @param event the event to log.  
*/
  public void callAppenders(LoggingEvent event) {
    int writes = 0;

    for(Category c = this; c != null; c=c.parent) {
      // Protected against simultaneous call to addAppender, removeAppender,...
      synchronized(c) {
	if(c.aai != null) {
	  writes += c.aai.appendLoopOnAppenders(event);
	}
	if(!c.additive) {
	  break;
	}
      }
    }

    if(writes == 0) {
      repository.emitNoAppenderWarning(this);
    }
  }

この方法にはsynchronized同期ロックがあり、同期ロックはスレッド競合を引き起こし、大きな同時性の場合、パフォーマンスの問題が発生すると同時に
スレッドBLOCKEDの問題が発生します.
Apache logを使用してこの問題を解決できます.コードは以下の通りです.
private static final Log log = LogFactory.getLog("xxx");  

テストに合格しましたorg.apache.log4j.Category.callAppendersスレッドBLOCKEDの問題はありません.
上記は非常に簡単な例にすぎず,現実の開発過程ではスレッドの状態に基づいて多くの問題を見つけることができる.試してみてください.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
本文はブロガーのオリジナル文章で、ブロガーの許可を得ずに転載してはならない.ブログアドレス:http://blog.csdn.net/mr_smile2014