如何避免DB2驱动程序Classloader内存泄漏Tomcat应用程序.war文件重新部署

时间:2015-12-10 21:57:22

标签: java tomcat db2 jndi connection-pooling

IBM受到良好支持的JDBC驱动程序与Tomcat支持良好的连接池一起创建了内存泄漏。 请参阅Classloader memory leak on Tomcat application .war file redeployment.

java.lang.IllegalStateException: Illegal access: this web application instance has been stopped already. Could not load [DB2JccConfiguration.properties]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
    at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading(WebappClassLoaderBase.java:1327)
    at org.apache.catalina.loader.WebappClassLoaderBase.getResource(WebappClassLoaderBase.java:1023)
    at com.ibm.db2.jcc.am.ud.run(Unknown Source)
    at java.security.AccessController.doPrivileged(AccessController.java:285)
    at com.ibm.db2.jcc.am.GlobalProperties.a(Unknown Source)
    at com.ibm.db2.jcc.am.GlobalProperties.d(Unknown Source)
    at com.ibm.db2.jcc.am.mq.run(Unknown Source)
    at java.util.TimerThread.mainLoop(Timer.java:567)
    at java.util.TimerThread.run(Timer.java:517)

我不理解建议的解决方案,因为它与在Tomcat lib目录中包含驱动程序jar的最推荐做法相冲突。

我们需要共享部署和重新部署,而无需重新启动Tomcat。如果您有使用此软件组合和所述问题的经验,请在此处分享您的解决方案。

3 个答案:

答案 0 :(得分:4)

对于驱动程序版本4.22.29,我目前在ServletContextListener中使用此代码:

@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
    // This fixes the JDBC driver not unloading corectly on a context reload  for DB2 JDBC 4.22.29
    try {
        logger.debug("Trying to stop the timer");
        new com.ibm.db2.jcc.am.iq() {
            // instance initializer to execute the fix when the anonymous class is instantiated, i.e. now
            {
                if (a != null) {
                    a.cancel();
                } else {
                    logger.debug("Timer is null, skipped");
                }
            }
        };
        logger.debug("Stopped the timer");
    } catch (Exception e) {
        logger.error("Could not stop the DB2 timer thread", e);
    }
}

注意:由于DB2驱动程序JAR似乎被混淆,因此其他驱动程序版本的计时器存储(com.ibm.db2.jcc.am.iq.a)可能会有所不同。此外,您子类化的类的构造函数可能有副作用,在我的情况下没有副作用。

我如何解决这个问题

获取例外

java.lang.NullPointerException
    at org.apache.catalina.loader.WebappClassLoaderBase.getResource(WebappClassLoaderBase.java:1600)
    at com.ibm.db2.jcc.am.wd.run(wd.java:49)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.ibm.db2.jcc.am.GlobalProperties.a(GlobalProperties.java:146)
    at com.ibm.db2.jcc.am.GlobalProperties.d(GlobalProperties.java:100)
    at com.ibm.db2.jcc.am.dr.run(dr.java:124)  <------- point of interest <----------
    at java.util.TimerThread.mainLoop(Timer.java:555)
    at java.util.TimerThread.run(Timer.java:505)

计时器的主要类是com.ibm.db2.jcc.am.dr

使用IntelliJ,我在其构造函数中设置了断点。等待断点点击:

instantiaed in GlobalProperties

转到它实例化的地方,在我的例子中是GlobalProperties。看看它的计划时间。

iq.a.schedule()

找到一种访问iq.a的方法:由于这是一个静态受保护的字段,我们可以从iq继承并从该类内部访问父类的静态字段以调用{{1在cancel()上。

答案 1 :(得分:1)

这是IBM JDBC驱动程序版本4.19中的已确认错误(无法禁用的计时器任务)。解决方法是降级到版本4.18。

答案 2 :(得分:1)

修订版本4.19.66:

    func textDidChange(_ notification: Notification) {
        print("Its come here textDidChange")
        guard (notification.object as? NSTextView) != nil else { return }
        let numberOfCharatersInTextfield: Int = textFieldCell.accessibilityNumberOfCharacters()
        print("numberOfCharatersInTextfield = \(numberOfCharatersInTextfield)")
}