2011-08-15 22 views
18

Tôi đang gặp khó khăn trong việc hiểu kết xuất chuỗi tôi nhận được từ jstack cho ứng dụng web Spring MVC chạy trên Tomcat 6 (java 1.6.0_22, Linux) .Kết thúc chuỗi Java: BLOCKED thread mà không phải "đang chờ khóa ..."

Tôi thấy các chủ đề chặn (khiến các chủ đề khác phải đợi) bị chặn, tuy nhiên kết xuất chuỗi không cho tôi biết lý do hoặc màn hình mà họ đang đợi.

Ví dụ:

"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) 
     ... 

Tức là Tôi đang thiếu dòng "chờ để khóa ..." trong dấu vết ngăn xếp. Rõ ràng là thread khóa một đối tượng Class, nhưng tôi không thấy lý do tại sao thread lại bị chặn.

Kết xuất đề xuất không chứa bất kỳ gợi ý nào cho deadlocks.

Tôi có thể làm gì để xác định màn hình khóa?

Cảm ơn, Oliver

+0

Bạn có thấy bất kỳ mục nhập nào khác để tham chiếu 0x00000000472bc000 không? –

+0

Không, không phải trong cùng một bãi chứa. 0x00000000472bc000 xác định chuỗi "TP-Processor75", vì vậy bạn có mong đợi nhiều đề cập của cùng một chuỗi trong kết xuất không? – Oliver

+0

Vâng 0x00000000472bc000 cho biết màn hình đang chờ để vào. Đó là một luồng khác đã nhập tham chiếu màn hình 0x00000000472bc000 và TP-Processor75 đang chờ chuỗi đang giữ để giải phóng 0x00000000472bc000 –

Trả lời

10

Rõ ràng tình huống mà chúng tôi quan sát các loại chủ đề chặn có liên quan đến tiêu thụ bộ nhớ lớn và thu gom rác thải do đó đồ sộ.

Câu hỏi này Java blocking issue: Why would JVM block threads in many different classes/methods? mô tả tình huống tương tự, vì vậy tôi tin rằng các chủ đề này đơn giản bị chặn bởi bộ thu gom rác.

(Dù sao, sau khi giải quyết vấn đề bộ nhớ vấn đề này với chủ đề chặn đã biến mất.)

2

Tôi đã có một vấn đề tương tự chỉ là bây giờ sử dụng một Applet trong Google Chrome.

Nói tóm lại:

  • Các chủ đề BLOCKED có thể bị chặn khi VM cần nạp một lớp.
  • Khi quá trình tải bản thân lớp bị chặn bởi một thứ gì đó bị đóng băng cho toàn bộ ứng dụng có thể xảy ra.

Trong Xem chi tiết:

tôi đã có tình huống sau:

  1. Tôi đang sử dụng một Applet trong Chrome với codebase = thư mục để đơn đẳng cấp file (không jar)
  2. Trang web chuyển các sự kiện trọng tâm tới applet bằng LiveConnect
  3. Các cuộc gọi JS đến đang sử dụng Executor với new Runnable() ... để de tach các cuộc gọi để giảm thời gian chờ đợi và do đó bị treo trong JS.
  4. Đó là nơi xảy ra sự cố!

Giải thích:

  • Các new Runnable() là một lớp bên trong annonymous mà đã không được nạp trước khi cuộc gọi JS xảy ra.
  • Cuộc gọi JS do đó kích hoạt tải lớp.
  • Nhưng bây giờ trình nạp lớp bị chặn vì nó cần nói chuyện với trình duyệt (tôi đoán) thông qua cùng một hàng đợi hoặc cơ chế đang xử lý cuộc gọi JS đến.

Đây là chủ đề bị chặn mà đang cố gắng tải các lớp:

"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) 

Như bạn có thể nhìn thấy nó đang chờ đợi một tin nhắn ->waitForMessage().

Đồng thời có JS cuộc gọi đến của chúng tôi bị chặn ở đây:

"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) 

bổ sung chủ đề khác đã bị chặn theo cách tương tự. Tôi cho rằng tất cả các yêu cầu tải lớp tiếp theo đã bị chặn bởi chuỗi tải lớp bị chặn đầu tiên.

Như đã đề cập trước đây, tôi đoán là quá trình tải lớp bị chặn bởi cuộc gọi JS đang chờ xử lý, mà chính nó bị chặn bởi lớp bị thiếu sẽ được tải.

Giải pháp:

  1. Kích hoạt tải tất cả các lớp học có liên quan trong constructor của applet trước bất kỳ cuộc gọi có thể được thực hiện từ JS.
  2. Nó có thể giúp đỡ nếu các tập tin lớp học không được tải riêng lẻ, nhưng từ một tập tin jar. Lý thuyết đằng sau này là: Trình nạp lớp không cần nói chuyện với trình duyệt để tải các lớp từ tệp jar (sẽ là
  3. Kết hợp với 1 .: Sử dụng lớp động Proxy để bao bọc tất cả các cuộc gọi JS đến và chạy chúng một cách độc lập trong một Executor

thực hiện của tôi cho # 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

Đây là một lỗi thẩm mỹ trong HotSpot JVM của Oracle - trong stack trace của bạn, nơi bạn nhìn thấy - locked <0x00007f3e9a0b3830> nó thực sự nên nói - waiting to lock <0x00007f3e9a0b3830>. .

Xem this bug để biết thêm chi tiết.

3

Kiểm tra xem chuỗi trình kết thúc có bị chặn hoặc đang chờ hay không.

Trong khi quét GC, GC sẽ "ngăn chặn thế giới" để thực hiện dọn dẹp. Định nghĩa về "thế giới" phụ thuộc vào bộ thu gom rác đang được sử dụng và ngữ cảnh. Nó có thể là một cụm chủ đề nhỏ hoặc tất cả chúng. Trước khi chính thức thu thập rác thải, GC sẽ triệu gọi đối tượng finalize().

Nếu bạn đang ở trong tình huống không mong muốn, nơi bạn đang triển khai phương pháp finalizer, mã hoàn thiện có thể chặn nó hoàn thành và dừng lại 'thế giới'. Điều này là rõ ràng nhất khi nhìn thấy rất nhiều chủ đề bị chặn vĩnh viễn bởi một số lực lượng ma thuật không xác định: Tra cứu mã nơi mà việc chặn xảy ra và nó sẽ không có ý nghĩa; không có mã chặn nào được tìm thấy ở bất kỳ nơi nào gần nó và các bãi chứa sẽ không tiết lộ những gì màn hình đang đợi vì không có. GC đã tạm dừng các chủ đề.

Các vấn đề liên quan