java - 如何避免 Tomcat 应用程序 .war 文件重新部署时的 DB2 驱动程序类加载器内存泄漏

标签 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)

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

我们需要在不重启 Tomcat 的情况下共享部署和重新部署。如果您对此软件组合和所描述的问题有经验,请在此处分享您的解决方案。

最佳答案

对于驱动程序版本 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继承并从该类内部访问静态字段在 a 上调用 cancel() 的父类。

关于java - 如何避免 Tomcat 应用程序 .war 文件重新部署时的 DB2 驱动程序类加载器内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34212501/

相关文章:

java - 使用Jsoup从网页中获取没有标签的文本

apache - session 在 apache2 ProxyPass 后面的 tomcat8 上过期

sql - 如何从db2中选择CLOB数据类型数据

sql - 将 DB2 查询转换为 Oracle 查询

c - Ubuntu 12.04 上的 IBM DB2 v10.1 找不到 C 头文件

java - 如何通过此 Activity 解决 : IllegalStateException: You need to use a Theme. AppCompat 主题(或后代)

Java 编译器优化

java - 如何获取单选按钮的值并在 TextView 上显示(Java for android)

java - JHipster:将根域重定向到 www

java - 如何删除fileupload struts2中的.tmp文件