Bug #41086 memory leak in mysql jdbc driver (with c3p0 pool)
Submitted: 28 Nov 2008 7:59 Modified: 22 May 2009 20:58
Reporter: ttt ttt Email Updates:
Status: Duplicate Impact on me:
None 
Category:Connector / J Severity:S2 (Serious)
Version:5.1.6 OS:Any
Assigned to: CPU Architecture:Any
Tags: c3p0, jdbc, Leak, Memory

[28 Nov 2008 7:59] ttt ttt
Description:
I use c3p0 connection / statement pool. The c3p0 pool never close the statement's, because the pool's job is it. In my program with this pool I detected a memory leak. I watched my program with a java profiler. Gc couldn't drop the ResultSet objects. I debuged the JDBC driver and found an interresting thing. The StatementImpl class store resultsets in the openResults variable. I found that, I can turn off this function with the dontTrackOpenResources=true parameter. 

BUT the StatementImpl.getGeneratedKeysInternal() method don't check this flag and in every case it put the resultset in the openResults variable.

I patched the StatementImpl.getGeneratedKeysInternal():
        if (!this.connection.getDontTrackOpenResources()) {
            this.openResults.add(gkRs);
        }
It works fine.

I think this is a bug, isn't it?

Sorry for my English, I hope the description is clear.

How to repeat:
I used hibernate + c3p0 pool + mysql jdbc 5.1.6.

When the hibernate insert an entity, the hibernate call statement what was the primary key. This statement cached (by c3p0), and the statement cached the resultset (by jdbc driver).
[6 Dec 2008 22:35] Tonci Grgin
Hi and thanks for your report.

I checked latest sources and same code is present there. It does look suspicious.

Verified as described by looking into latest sources, the StatementImpl.getGeneratedKeysInternal() method doesn't check getDontTrackOpenResources flag when assigning openResults.
[12 Feb 2009 22:41] James Avery
I think this is a far more serious memory leak and not necessarily related to the "dontTrackOpenResources" configuration option.

For example, if I use the same prepared statement (e.g. an insert statement) over and over again (which is normal for a prepared statement), each time calling getGeneratedKeys like so:

ResultSet keyResultSet = insertStmt.getGeneratedKeys();
if (keyResultSet.next())
{
   id = keyResultSet.getInt(1);
}
keyResultSet.close();

It will eventually result in an out of memory condition.  This is because calling "keyResultSet.close()" does not remove the entry from the StatementImpl.openResults ArrayList.
[13 Feb 2009 7:55] Tonci Grgin
James, I agree thus one of the most severe triages I've ever set (although you see only D2(Serious).
[22 May 2009 20:58] Mark Matthews
Already fixed for Bug#44056 (duplicate)