Bug 54732 - StatementCache interceptor does not forward calls to Statement.close() which causes memory leaks
Summary: StatementCache interceptor does not forward calls to Statement.close() which ...
Status: RESOLVED FIXED
Alias: None
Product: Tomcat Modules
Classification: Unclassified
Component: jdbc-pool (show other bugs)
Version: unspecified
Hardware: PC All
: P2 major (vote)
Target Milestone: ---
Assignee: Tomcat Developers Mailing List
URL:
Keywords:
: 54337 (view as bug list)
Depends on:
Blocks:
 
Reported: 2013-03-20 16:09 UTC by berniegp
Modified: 2013-03-22 21:35 UTC (History)
2 users (show)



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description berniegp 2013-03-20 16:09:31 UTC
ML ref: http://mail-archives.apache.org/mod_mbox/tomcat-users/201303.mbox/browser

When using Tomcat's jdbc-pool with the StatementCache interceptor (the default for TomEE 1.5.1), the actual java.sql.Statement.close() method is not called on the Statements. This causes severe memory leaks, at least with the MySQL driver.

I see what could be a bug in StatementCache#closeInvoked() which is called by the above method. Here is the code with my own comments added:
@Override
public void closeInvoked() {
    boolean shouldClose = true;
    if (cacheSize.get() < maxCacheSize) {
        // omitted for brievety
    }
    closed = true;
    // [1] I think "delegate = null" is done too soon
    delegate = null;
    if (shouldClose) {
        // check its body below
        super.closeInvoked();
    }
}

// This is super.closeInvoked()
public void closeInvoked() {
    if (getDelegate()!=null) {
        // never true when coming from
        // StatementCache#closeInvoked()
        // because of [1]
        try {
            getDelegate().close();
        }catch (SQLException ignore) {
        }
    }
    closed = true;
    delegate = null;
}

To test this, step into org.apache.tomcat.jdbc.test.TestStatementCache tests testPreparedStatementCache and testPreparedStatementCache2. The calls to Statement.close() are intercepted but never forwarded to the actual Statement. Perhaps some kind of mock could be used to make sure Statement.close() is called on each created Statement.
Comment 1 Konstantin Kolinko 2013-03-22 13:45:54 UTC
Confirmed.
The leak happens when the cache is full, so the statement that is being closed cannot be returned to the cache but has to be closed right away.

Fixed in trunk with r1459769
Comment 2 Konstantin Kolinko 2013-03-22 17:34:11 UTC
*** Bug 54337 has been marked as a duplicate of this bug. ***
Comment 3 Konstantin Kolinko 2013-03-22 21:35:28 UTC
Fixed in Tomcat 7 by r1460006 and will be in 7.0.40.