2011-08-15 14 views
18

スレッドダンプの理解に困っています。私はjstackからTomcat 6(Java 1.6.0_22、Linux)上で動作するSpring MVC Webアプリケーションを入手しました。 。Javaスレッドのダンプ: "ロックするのを待っていない..."

自分自身でブロックされているブロッキングスレッド(他のスレッドを待機させる)が表示されますが、スレッドダンプではなぜ、どのモニターが待機しているのかはわかりません。

例:

"TP-Processor75" daemon prio=10 tid=0x00007f3e88448800 nid=0x56f5 waiting for monitor entry [0x00000000472bc000] 
    java.lang.Thread.State: BLOCKED (on object monitor) 
     at java.lang.Class.initAnnotationsIfNecessary(Class.java:3067) 
     - locked <0x00007f3e9a0b3830> (a java.lang.Class for org.catapultframework.resource.ResourceObject) 
     at java.lang.Class.getAnnotation(Class.java:3029) 
     ... 

すなわち、私は、スタックトレースの "ロックを待っています..."という行がありません。どうやら、スレッドはClassオブジェクトをロックしていますが、スレッド自体がブロックされている理由はわかりません。

スレッドダンプにはデッドロックのヒントは含まれていません。

ロックモニタを特定するにはどうすればよいですか?

おかげで、 オリバー

+0

参照0x00000000472bc000の他のエントリがありますか? –

+0

いいえ、同じダンプにはありません。 0x00000000472bc000はスレッド "TP-Processor75"を識別します。そのため、ダンプ内の同じスレッドの複数の記述が必要ですか? – Oliver

+0

よく0x00000000472bc000は、スレッドが入力待ちのモニターを示します。つまり、別のスレッドがモニタ参照0x00000000472bc000に入っており、TP-Processor75が現在保持しているスレッドが0x00000000472bc000を解放するのを待っている –

答えて

10

我々がブロックされたスレッドのこれらの種類が重いメモリ消費ため、大規模なガベージコレクションに関連していた観察どうやら状況。

この質問Java blocking issue: Why would JVM block threads in many different classes/methods?は同様の状況を示しているため、これらのスレッドは単にガベージコレクタによってブロックされたと考えられます。

(とにかく、メモリの問題を解決した後に、ブロックされたスレッドで、この問題は消えていた。)

2

私はちょうど今、Google Chromeでアプレットを使用して同様の問題がありました。要するに

:VMがクラスをロードする必要があるとき

  • ブロックされたスレッドをブロックすることができます。
  • クラス自体をロードするプロセスが何かによってブロックされると、アプリケーション全体がフリーズすることがあります。詳細に

私は次のようなシナリオだった:私は、単一のクラス・ファイルにコードベース=フォルダ(なしのjar)

  • とChromeでアプレットを使用しています

    1. をウェブサイトはLiveConnectを使用してフォーカスイベントをアプレットに渡します
    2. 着信JSコールはExecutornew Runnable() ...を使用しています待ち時間を減らすためにコールをタックし、JSでハングアップします。
    3. ここで問題が発生しました。

    説明:

    • new Runnable()はJSコールが起こったの前にロードされていませんでしたAnnonymousの内部クラスです。
    • JSコールは、クラスロードをトリガーします。
    • しかし、クラスローダーは、着信JS呼び出しを処理しているのと同じキューまたはメカニズムを介してブラウザと話す必要があるため(私は推測している)、ブロックされています。ここで

    クラスをロードしようとしているブロックされたスレッドです:あなたはそれがメッセージを待っている見ることができるように

    "Thread-20" daemon prio=4 tid=0x052e8400 nid=0x4608 in Object.wait() [0x0975d000] 
        java.lang.Thread.State: WAITING (on object monitor) 
        at java.lang.Object.wait(Native Method) 
        at sun.plugin2.message.Queue.waitForMessage(Unknown Source) 
        - locked <0x29fbc5d8> (a sun.plugin2.message.Queue) 
        at sun.plugin2.message.Pipe$2.run(Unknown Source) 
        at com.sun.deploy.util.Waiter$1.wait(Unknown Source) 
        at com.sun.deploy.util.Waiter.runAndWait(Unknown Source) 
        at sun.plugin2.message.Pipe.receive(Unknown Source) 
        at sun.plugin2.main.client.MessagePassingExecutionContext.doCookieOp(Unknown Source) 
        at sun.plugin2.main.client.MessagePassingExecutionContext.getCookie(Unknown Source) 
        at sun.plugin2.main.client.PluginCookieSelector.getCookieFromBrowser(Unknown Source) 
        at com.sun.deploy.net.cookie.DeployCookieSelector.getCookieInfo(Unknown Source) 
        at com.sun.deploy.net.cookie.DeployCookieSelector.get(Unknown Source) 
        - locked <0x298da868> (a sun.plugin2.main.client.PluginCookieSelector) 
        at sun.net.www.protocol.http.HttpURLConnection.setCookieHeader(Unknown Source) 
        at sun.net.www.protocol.http.HttpURLConnection.writeRequests(Unknown Source) 
        at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source) 
        - locked <0x2457cdc0> (a sun.net.www.protocol.http.HttpURLConnection) 
        at com.sun.deploy.net.HttpUtils.followRedirects(Unknown Source) 
        at com.sun.deploy.net.BasicHttpRequest.doRequest(Unknown Source) 
        at com.sun.deploy.net.BasicHttpRequest.doGetRequestEX(Unknown Source) 
        at com.sun.deploy.cache.ResourceProviderImpl.checkUpdateAvailable(Unknown Source) 
        at com.sun.deploy.cache.ResourceProviderImpl.isUpdateAvailable(Unknown Source) 
        at com.sun.deploy.cache.DeployCacheHandler.get(Unknown Source) 
        - locked <0x245727a0> (a java.lang.Object) 
        at sun.net.www.protocol.http.HttpURLConnection.plainConnect(Unknown Source) 
        at sun.net.www.protocol.http.HttpURLConnection.connect(Unknown Source) 
        at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source) 
        - locked <0x24572020> (a sun.net.www.protocol.http.HttpURLConnection) 
        at java.net.HttpURLConnection.getResponseCode(Unknown Source) 
        at sun.plugin2.applet.Applet2ClassLoader.getBytes(Unknown Source) 
        at sun.plugin2.applet.Applet2ClassLoader.access$000(Unknown Source) 
        at sun.plugin2.applet.Applet2ClassLoader$1.run(Unknown Source) 
        at java.security.AccessController.doPrivileged(Native Method) 
        at sun.plugin2.applet.Applet2ClassLoader.findClass(Unknown Source) 
        at sun.plugin2.applet.Plugin2ClassLoader.loadClass0(Unknown Source) 
        at sun.plugin2.applet.Plugin2ClassLoader.loadClass(Unknown Source) 
        - locked <0x299726b8> (a sun.plugin2.applet.Applet2ClassLoader) 
        at sun.plugin2.applet.Plugin2ClassLoader.loadClass(Unknown Source) 
        - locked <0x299726b8> (a sun.plugin2.applet.Applet2ClassLoader) 
        at java.lang.ClassLoader.loadClass(Unknown Source) 
    

    - >waitForMessage()

    "Applet 1 LiveConnect Worker Thread" prio=4 tid=0x05231800 nid=0x1278 waiting for monitor entry [0x0770e000] 
        java.lang.Thread.State: BLOCKED (on object monitor) 
        at MyClass.myMethod(MyClass.java:23) 
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) 
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) 
        at java.lang.reflect.Method.invoke(Unknown Source) 
        at sun.plugin.javascript.Trampoline.invoke(Unknown Source) 
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) 
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) 
        at java.lang.reflect.Method.invoke(Unknown Source) 
        at sun.plugin.javascript.JSClassLoader.invoke(Unknown Source) 
        at sun.plugin2.liveconnect.JavaClass$MethodInfo.invoke(Unknown Source) 
        at sun.plugin2.liveconnect.JavaClass$MemberBundle.invoke(Unknown Source) 
        at sun.plugin2.liveconnect.JavaClass.invoke0(Unknown Source) 
        at sun.plugin2.liveconnect.JavaClass.invoke(Unknown Source) 
        at sun.plugin2.main.client.LiveConnectSupport$PerAppletInfo$DefaultInvocationDelegate.invoke(Unknown Source) 
        at sun.plugin2.main.client.LiveConnectSupport$PerAppletInfo$3.run(Unknown Source) 
        at java.security.AccessController.doPrivileged(Native Method) 
        at sun.plugin2.main.client.LiveConnectSupport$PerAppletInfo.doObjectOp(Unknown Source) 
        at sun.plugin2.main.client.LiveConnectSupport$PerAppletInfo$LiveConnectWorker.run(Unknown Source) 
        at java.lang.Thread.run(Unknown Source) 
    

    追加、他のスレッドが同じ方法でブロックされました:ここにブロックされて私たちの着信JSの呼び出しがあると同時に

    。私はすべての後続のクラスロード要求が最初にブロックされたクラスローディングスレッドによってブロックされたと仮定します。

    私が推測したように、クラスローディングプロセスは、ロードされる欠落クラスによってブロックされている保留中のJS呼び出しによってブロックされます。

    ソリューション:すべての呼び出しの前に、アプレットのコンストラクタで、関連するすべてのクラスをロード

    1. トリガーはJSから作ることができます。
    2. クラスファイルが個別に読み込まれるのではなく、jarファイルから読み込まれる場合に役立ちます。この背後にある理論は次のとおりです。クラスローダーは、jarファイルからクラスをロードするためにブラウザと通信する必要はありません(
    3. 1と組み合わせて:動的なProxyクラスを使用して、そしてExecutorに独立してそれらを実行

    を#3のための私の実装:

    public class MyClass implements JsCallInterface 
    { 
    
        private final JsCallInterface jsProxy; 
    
        private final static interface JsCallInterface 
        { 
         public void myMethod1Intern(String param1, String param2); 
        } 
    
        private final class JsCallRunnable implements Runnable 
        { 
    
         private final Method method; 
         private final Object[] args; 
    
         private JsCallRunnable(Method method, Object[] args) 
         { 
          this.method = method; 
          this.args = args; 
         } 
    
         public void run() 
         { 
          try 
          { 
           method.invoke(MyClass.this, args); 
          } 
          catch (Exception e) 
          { 
           e.printStackTrace(); 
          } 
         } 
        } 
    
        public MyClass() 
        { 
         MyUtilsClass.class.getName(); // load class 
         JsCallRunnable.class.getName(); // load class 
         InvocationHandler jsCallHandler = new InvocationHandler() 
         { 
    
          public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable 
          { 
           MyUtilsClass.executeInExecutor(new JsCallRunnable(method, args)); 
           return null; 
          } 
    
         }; 
         jsProxy = (JsCallInterface) Proxy.newProxyInstance(MyClass.class.getClassLoader(), new Class<?>[] { JsCallInterface.class }, jsCallHandler); 
        } 
    
        public void myMethod1(String param1, String param2) 
        { 
         jsProxy.myMethod1Intern(param1, param2); 
         // needs to be named differently than the external method or else the proxy will call this method recursively 
         // alternatively the target-class in "method.invoke(MyClass.this, args);" could be a different instance of JsCallInterface 
        } 
    
        public void myMethod1Intern(String param1, String param2) 
        { 
         // do actual work here 
        } 
    } 
    
  • 0

    これは、OracleのHotSpot JVMで化粧バグです - あなたが- locked <0x00007f3e9a0b3830>を参照してくださいあなたのスタックトレースにそれが実際に- waiting to lock <0x00007f3e9a0b3830>を言う必要があります。 。

    詳細はthis bugを参照してください。

    3

    ファイナライザスレッドがブロックされているか待機しているかを確認してください。

    GCスイープ中、GCはクリーンアップを実行するために「世界を止めます」。 「世界」の定義は、使用されているガベージコレクタとコンテキストに依存します。小さなスレッドのクラスタでも、すべてのスレッドでも構いません。ゴミを正式に収集する前に、GCはオブジェクトのfinalize()を呼び出します。

    ファイナライザメソッドを実装していると望ましくない状況にある場合、ファイナライゼーションコードによってフィニッシュがブロックされ、「ワールド」が停止している可能性があります。

    これは、不明な魔法の力によって永続的にブロックされているスレッドが多数ある場合に最もよくわかります。ブロッキングが発生したコードを調べれば意味がありません。その近くにはどこにも見つからないブロッキングコードはなく、ダンプは何もないので待機しているモニターを漏らしません。 GCがスレッドを一時停止しました。

    関連する問題