JVM试图获取信号量而陷入困境

时间:2016-01-11 01:58:11

标签: java windows jvm jetty semaphore

我有一个使用嵌入式Jetty(版本9.3.6.v20151106)和JDK 8u65的应用程序。

当我在Mac或Linux上使用此应用程序时,我没有遇到任何困难。但是在Windows上,Jetty无法启动,应用程序将永久挂起。

我在进程上运行了一个jstack命令并隔离了阻止服务器启动的线程。

java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x1a3b2018> (a java.util.concurrent.Semaphore$NonfairSync)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:997)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1304)
    at java.util.concurrent.Semaphore.acquire(Semaphore.java:312)
    at org.eclipse.jetty.annotations.AnnotationConfiguration.scanForAnnotations(AnnotationConfiguration.java:540)
    at org.eclipse.jetty.annotations.AnnotationConfiguration.configure(AnnotationConfiguration.java:447)
    at org.eclipse.jetty.webapp.WebAppContext.configure(WebAppContext.java:491)
    at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1336)

我找了另一个阻止锁的线程,但没有。

如何进一步调试此问题?它是JVM错误还是Windows安全功能?非常感谢任何帮助。

3 个答案:

答案 0 :(得分:1)

Windows似乎无法正确报告处理器数量。 尝试将org.eclipse.jetty.annotations.multiThreaded属性设置为false,看看是否有帮助。

答案 1 :(得分:1)

事实证明我对自己的日志视而不见。我发现在扫描应用程序的jar时我正在抛出OOM。 有很多因素可以解释为什么这种情况会在Windows上发生。首先,这是一个32位发行版,所以它在内存方面有点反复无常。 Java的最大堆大小最终会受到影响。

正如在#jetty IRC频道上所讨论的那样(由于他的精彩帮助而得到joakime的称赞和赞誉),这是由于jar扫描应用程序的WEB-INF / lib。这会增加启动时间,如果你有大量的垃圾文件罐,可能会导致OOM。

joakime指出了解决问题的两种可能性:

  • 预包装并准备更多应用,并使用quickstart
  • 使用正则表达式有意识地扫描罐子以选择要扫描的那些(此page的底部)

我最终使用了后者。我使用这个正则表达式匹配jstl jar和spring jar(我使用springl的jarlibs jar):

".*/jstl-[^/]*\\.jar$|.*/spring-[^/]*\\.jar$"

答案 2 :(得分:0)

  

我找了另一个阻止锁的线程,但没有。

信号量比锁更通用。这是一堆许可,不一定与任何瘦身有关。它们可以由一个或多个线程获取和释放,并且不需要在已完成获取的线程上发布。

一个线程甚至可以创建一个信号量,消耗所有可用的许可,然后等待它自己的信号量而没有另一个线程接触它。

因此,通过查找“持有锁”的其他线程,无法轻松完成调试信号量。

要调试它们,您必须跟踪获取和发布,并查看许可证耗尽的位置,然后找出它们应该被释放的位置,但不是。