我们为在 Tomcat 6.0.28 和 OpenJDK 运行时环境 (IcedTea6 1.11.11) 上运行的新版 Java EE Web 应用程序运行了几个浸泡测试。问题出现在 Web 层。
一段时间后 - 第一次 50 分钟,第二次 1 小时,第三次 2.5 小时 - 我们的集群 Web 层中的一个随机 Tomcat 停止响应。查看线程转储,我们看到大量线程突然阻塞。
当问题发生时,线程数从 93 增加到 437。437 个线程中的 341 个在 WebappClassLoader 上被阻塞,如下所示:
"TP-Processor400" daemon prio=10 tid=0x00007f1ee432e800 nid=0x44d9 waiting for monitor entry [0x00007f1ec47c5000]
java.lang.Thread.State: BLOCKED (on object monitor)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java)
- waiting to lock <0x00000006f561a758> (a org.apache.catalina.loader.WebappClassLoader)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1329)
一个线程持有锁:
"TP-Processor53" daemon prio=10 tid=0x00007f1ee406f800 nid=0x7cbf runnable [0x00007f1f4545b000]
java.lang.Thread.State: RUNNABLE
at java.lang.ClassLoader.findLoadedClass0(Native Method)
at java.lang.ClassLoader.findLoadedClass(ClassLoader.java:923)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1386)
- locked <0x00000006f561a758> (a org.apache.catalina.loader.WebappClassLoader)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1329)
每隔一分钟的后续线程转储显示锁正在被释放,然后被其他线程获取。2 分钟后,所有阻塞的线程都被解除阻塞,服务器再次正常运行。
WebappClassLoader 的死锁问题已在 Tomcat 错误跟踪器上报告,应用程序使用自己的类加载器(https://issues.apache.org/bugzilla/show_bug.cgi?id=48694与https://issues重复.apache.org/bugzilla/show_bug.cgi?id=48903),这也是我们的情况:我们的应用程序嵌入在集群的 OpenCMS 安装中,该安装使用 org.opencms.ocee.base.CmsReloadingClassLoader 加载类。
当阻塞发生时,我们还看到 GC 活动从 CPU 时间的 10% 增加到 50%,即使当时内存和堆没有增加。
问题是这种阻塞可能是由什么引起的,我们可以做些什么来解决它?