Bug #10954 Memory leak
Submitted: 30 May 2005 9:21 Modified: 31 May 2005 13:50
Reporter: Peter Salomonsen Email Updates:
Status: Won't fix Impact on me:
None 
Category:Connector / J Severity:S1 (Critical)
Version:3.1.8a OS:Linux (Linux)
Assigned to: CPU Architecture:Any

[30 May 2005 9:21] Peter Salomonsen
Description:
According to the documentation of the java.sql.Statement interface a statement is automatically closed on garbage collection. This is not happening in the 3.1.8a release, but it was ok in the 3.0 series.

How to repeat:
Use the code below to reproduce the memory leak behavior. When the same code was running on 3.0.11, the memory usage was constant. On 3.1.8a the memory usage is increasing - but it should not as a garbage collection is forced after each statement creation.

import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;

    /**
     * @author Peter Salomonsen
     */

public class MemoryUsageMonitor {    
    public static void main(String[] args) throws Exception  {
        MemoryMXBean mx = ManagementFactory.getMemoryMXBean();
        
        mx.setVerbose(true);
        
        Driver driver = (Driver)
        Class.forName("com.mysql.jdbc.Driver").newInstance();
        DriverManager.registerDriver(driver);

        Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "username", "password");
        
        while(true)
        {
            System.out.println(mx.getHeapMemoryUsage());
            con.createStatement().execute("SELECT 1");
            mx.gc();
        }
    }
}
[30 May 2005 10:06] Vasily Kishkin
Tested on Win 2000 Sp4 , JDK 1.5. Test case is attached.
[30 May 2005 10:06] Vasily Kishkin
Test case

Attachment: MemoryUsageMonitor.java (text/plain), 897 bytes.

[31 May 2005 13:50] Mark Matthews
We won't can't fix this for the following reasons:

1) The requirement is not practically implementable, as it is a) At odds with other requirements in the JDBC specification, specifically regarding Connection.close() closing open statements and Statement.close() closing open result sets and b) The contract for finalize() is at odds with the cleanup that a database driver has to do to release _server-side_ resources. As a reminder, here's the verbiage from the apidocs:

"It is guaranteed, however, that the thread that invokes finalize will not be holding any user-visible synchronization locks when finalize is invoked. If an uncaught exception is thrown by the finalize method, the exception is ignored and finalization of that object terminates."

Unfortunately, because of this condition, a driver can _not_ communicate with the server to release resources and because of the following condition in the VM spec, even if the above statement weren't true, almost any JDBC driver would very often end up in deadlock as it needs operations to be called in a certain defined order to serialize access to the connection when sending commands to the server:

"The Java virtual machine imposes no ordering on finalize method calls. Finalizers may be called in any order or even concurrently."

Because of the issues that point (1) brings to the table, _all_ vendors on the JDBC-4.0 experts' group have voted to _remove_ the requirement from JDBC-4.0.

2) It greatly impacts performance. Within a JDBC driver's code path, our internal benchmarks have shown that even with a finalize() method that does _nothing_, an application will experience a throughput impact of 25-30%, with all of the time being spent in java.lang.Ref.registerFinalizer(Object), which means there is _no_ way to avoid it if finalizers are used, even if they do nothing.

Point (2) is an unacceptable performance impact for the large majority of the user population who don't rely on this requirement. Since this requirement will be removed soon for all JDBC drivers, we'd recommend that if your application absolutely needs these semantics that you wrap the resources returned from Connection.create/prepareStatement() and Statement.execute*() with your own abstractions that have finalizers associated with them.
[5 Jan 2007 20:31] Lucian Cioranu
I busted my a.. to find the memory leak in my code(using MySql connector 5.0). Lucky me that I found this page. Thanks a lot Peter Salomonsen.