You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by bu...@apache.org on 2015/11/04 23:51:33 UTC

[Bug 58586] New: Classloader memory leak on Tomcat application .war file redeployment.

https://bz.apache.org/bugzilla/show_bug.cgi?id=58586

            Bug ID: 58586
           Summary: Classloader memory leak on Tomcat application .war
                    file redeployment.
           Product: Tomcat Modules
           Version: unspecified
          Hardware: All
                OS: AIX
            Status: NEW
          Severity: major
          Priority: P2
         Component: jdbc-pool
          Assignee: dev@tomcat.apache.org
          Reporter: bht237@gmail.com

The leak can be observed with the use of the latest version of an IBM jdbc
driver.

IBM support have worked on the issue for us. Their resolution is to deregister
the JDBC driver with a ServletContextListener.

Additionally they recommend to include the driver jar db2jcc4.jar in the web
archive WEB-INF/lib directory.                                                  

Unfortunately while doing this as recommended, the exception below still
appears once per second in the log file:

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)

Environment information is as follows:

Tomcat version: 8.0

Operating system: AIX

java -version
java version "1.7.0"
Java(TM) SE Runtime Environment (build pap6470sr7-20140410_01(SR7))
IBM J9 VM (build 2.6, JRE 1.7.0 AIX ppc64-64 Compressed References
20140409_195732 (JIT enabled, AOT enabled)
J9VM - R26_Java726_SR7_20140409_1418_B195732
JIT  - r11.b06_20140409_61252
GC   - R26_Java726_SR7_20140409_1418_B195732_CMPRSS
J9CL - 20140409_195732)
JCL - 20140409_01 based on Oracle 7u55-b13


JDBC driver downloaded from:
http://www-01.ibm.com/support/docview.wss?uid=swg21363866
DB2 JDBC and SQLJ driver 10.5.0
v10.5fp5_jdbc_sqlj.tar.gz

Configuration is as follows:

A data source is defined in the Tomcat application context:

$CATALINA_BASE/conf/Catalina/localhost/db2test.xml as follows:

<?xml version="1.0" encoding="UTF-8"?>
<Context>
    <Resource name="jdbc/db2test"
          auth="Container"
          type="javax.sql.DataSource"
          username="username"
          password="password"
          driverClassName="com.ibm.db2.jcc.DB2Driver"
          url="jdbc:db2://server:port/databaseName:currentSchema=schemaName;"
          maxActive="8"
    />
</Context>

web.xml as follows:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <display-name>Leaky Application</display-name>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <listener>
        <listener-class>
            connect.listener.DatabaseGetConnectionContextListener
        </listener-class>
    </listener>
    <listener>
        <listener-class>
            connect.listener.DeregisterDriverServletContextListener
        </listener-class>
    </listener>
</web-app>

with listeners as follows:

public class DatabaseGetConnectionContextListener implements
ServletContextListener {

    private static final Logger LOGGER =
LoggerFactory.getLogger(DatabaseGetConnectionContextListener.class);

    public void contextInitialized(ServletContextEvent sce) {
        LOGGER.info("contextInitialized trying to get connection...");
        try {
            Context initCtx = new InitialContext();
            Context envCtx = (Context) initCtx.lookup("java:comp/env");
            DataSource ds = (DataSource) envCtx.lookup("jdbc/db2test");
            Connection con = null;
            try {
                con = ds.getConnection();
                LOGGER.info("Opened connection: " + con);
            } catch (SQLException ex) {
                LOGGER.error("Cannot open connection", ex);
            } finally {
                if (con != null) {
                    try {
                        con.close();
                        LOGGER.info("Closed connection: " + con);
                    } catch (SQLException ex) {
                        throw new RuntimeException(ex);
                    }
                }
            }
        } catch (NamingException ex) {
            throw new RuntimeException(ex);
        }
    }

    public void contextDestroyed(ServletContextEvent sce) {}

}


public class DeregisterDriverServletContextListener implements
ServletContextListener {

    private static final Logger LOGGER =
LoggerFactory.getLogger(DeregisterDriverServletContextListener.class);

    public void contextInitialized(ServletContextEvent sce) {}

    @Override
    public void contextDestroyed(ServletContextEvent sce) {

        LOGGER.info("contextDestroyed() executing ...");
        final ClassLoader classLoader =
Thread.currentThread().getContextClassLoader();
        // Loop through all drivers                                           
        final Enumeration<Driver> drivers = DriverManager.getDrivers();
        while (drivers.hasMoreElements()) {
            final Driver driver = drivers.nextElement();
            if (driver.getClass().getClassLoader() == classLoader) {
                // This driver was registered by the webapp's ClassLoader, so   
                // deregister it:                                               
                try {
                    LOGGER.info("Deregistering JDBC driver { " + driver + "
}");
                    DriverManager.deregisterDriver(driver);
                } catch (SQLException ex) {
                    LOGGER.error("Error deregistering JDBC driver { " + driver
+ " }", ex);
                }
            } else {
                // driver was not registered by the webapp's ClassLoader and
may    
                // be in use elsewhere                                          
                LOGGER.error("Not deregistering JDBC driver {} as it does not
belong to this webapp's ClassLoader { " + driver + " }");
            }
        }
    }

db2jcc4.jar is in the WEB-INF/lib directory.

When the war file is re-deployed e.g. vie UNIX touch command, the following log
entries are printed in catalina.out:
INFO: Reloading Context with name [/db2test] has started
Nov 04, 2015 3:21:57 PM org.apache.catalina.loader.WebappClassLoaderBase
clearReferencesThreads
WARNING: The web application [db2test] appears to have started a thread named
[Timer-0] but has failed to stop it. This is very likely to create a memory
leak. Stack trace of thread:
 java.lang.Object.wait(Native Method)
 java.lang.Object.wait(Object.java:196)
 java.util.TimerThread.mainLoop(Timer.java:564)
 java.util.TimerThread.run(Timer.java:517)
Nov 04, 2015 3:21:59 PM org.apache.catalina.core.StandardContext reload
INFO: Reloading Context with name [/db2test] is completed
Nov 04, 2015 3:22:44 PM org.apache.catalina.loader.WebappClassLoaderBase
checkStateForResourceLoading
INFO: 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.
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 pur
poses 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)

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 pur
poses 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)
Nov 04, 2015 3:23:44 PM org.apache.catalina.loader.WebappClassLoaderBase
checkStateForResourceLoading
INFO: 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.
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 pur
poses 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)
....
More of the same repeats every minute.

We have tried an alternate configuration method as follows:

/conf/context.xml file as follows:
<Context>
   ...
    <Resource auth="Container"
    driverClassName="com.ibm.db2.jcc.DB2Driver"
    name="jdbc/..."
    password="..."
    username="..."
    type="javax.sql.DataSource"
    url="jdbc:db2://server:.../.../>
 ...
</Context>

and a resource link via db2test.xml

<?xml version="1.0" encoding="UTF-8"?>

<Context>

    <ResourceLink name="jdbc/db2test" global="jdbc/db2test"
type="javax.sql.DataSource"/>

</Context>


The results are the same.

Again, alternatively, the resource can be defined in server.xml, and a
<ResourceLink, again with no changes in web.xml
We have NOT tried this as we do not prefer this solution.

We used documentation at
https://tomcat.apache.org/tomcat-8.0-doc/jndi-resources-howto.html
https://www-01.ibm.com/support/knowledgecenter/SSZH4A_5.0.5/com.ibm.worklight.help.doc/admin/t_configuring_apache_tomcat_for_db2_manually.html
https://numberformat.wordpress.com/2009/09/07/db2-datasource-configuration-in-tomcat-6/

In addition to what we see, the proposed workaround (which I cannot get to
work), from my current perspective, has 2 issues:

a) No other application can use the same data source because it is local
b) Including a specific driver file in the application is not consistent with
the concept of a data source which from the application perspective, should not
be driver specific.

The attached file contains as a fully functional test case a minimal maven
based web project where a ServletContextListener connects to the data source on
start up and deregisters the driver on un-deployment.

Configuration files are also included, please refer to configuration
directories.

-- 
You are receiving this mail because:
You are the assignee for the bug.

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 58586] Classloader memory leak on Tomcat application .war file redeployment.

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=58586

--- Comment #1 from bernard <bh...@gmail.com> ---
Created attachment 33259
  --> https://bz.apache.org/bugzilla/attachment.cgi?id=33259&action=edit
Test case in zip archive

I had to remove the driver file db2jcc4.jar from the WEB-INF/lib directory
because of bugzilla upload file size restriction

-- 
You are receiving this mail because:
You are the assignee for the bug.

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 58586] Classloader memory leak on Tomcat application .war file redeployment.

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=58586

Mark Thomas <ma...@apache.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
         Resolution|---                         |INVALID
             Status|NEW                         |RESOLVED

--- Comment #2 from Mark Thomas <ma...@apache.org> ---
Memory leaks in JDBC drivers are not bugs in Tomcat. Please use the users
mailing list if you require further assistance.

This may provide someuseful background:
http://people.apache.org/~markt/presentations/2010-11-04-Memory-Leaks-60mins.pdf

-- 
You are receiving this mail because:
You are the assignee for the bug.

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org