使用JDBC的内存泄漏应用程序

时间:2012-09-03 00:52:17

标签: java mysql jdbc memory-leaks

我正在使用 mysql-connector-java-5.1.21 ,我得到内存泄漏,Memory Analyzer怀疑java.lang.Class和最大的实例 mysql。 jdbc 出现了。我已经完成了代码并确保所有连接,结果和语句都被正确关闭,我仍然会泄漏。

1,529 instances of "java.lang.Class", loaded by "<system class loader>" occupy 711,632 (41.68%) bytes. 

Biggest instances:
•class com.mysql.jdbc.NonRegisteringDriver @ 0x381323f8 - 97,400 (5.70%) bytes. 
•class java.io.ObjectStreamClass$Caches @ 0x3d070568 - 91,872 (5.38%) bytes. 
•class java.lang.System @ 0x3d03da20 - 67,224 (3.94%) bytes. 
•class com.mysql.jdbc.SingleByteCharsetConverter @ 0x382a7438 - 66,032 (3.87%) bytes. 
•class java.lang.ref.Finalizer @ 0x3d03e260 - 65,888 (3.86%) bytes. 
•class com.sun.org.apache.xerces.internal.util.XMLChar @ 0x380bc528 - 65,592 (3.84%) bytes. 
•class com.mysql.jdbc.ConnectionPropertiesImpl @ 0x381ab5f8 - 32,456 (1.90%) bytes. 

代码在一个有延迟的循环中运行。目前,代码每个间隔打开一个连接。我应该打开一个连接并将其传递给我的方法吗?无论哪种方式,我不知道为什么会导致泄漏。任何帮助表示赞赏。

这里有一些代码,它应该让你很好地了解我如何使用jdbc和mysql。

    try {


        url+=database+"?zeroDateTimeBehavior=convertToNull"; 
        // LatestTime in SQL table defaults 0000-00-00 00:00:00 which java can't handle. zeroDateTimeBehaviour=convertToNull cause JDBC to null for a zero date.

        Class.forName("com.mysql.jdbc.Driver").newInstance();
        conn = DriverManager.getConnection(url,user,password);
        System.out.println(CurrentTime()+": "+"Connected to "+database);
    }
    catch (Exception e)     
    {

            System.err.println(CurrentTime()+": "+e.getMessage());
            System.err.println(CurrentTime()+": "+"Unable to Connect");
    }
    finally
    {
        if (conn!=null)
        {
            try {
                // Create Statements for SQL queries
                Statement query= conn.createStatement();

                // Get all records from phonelog which have yet to be processed
                query.executeQuery("SELECT * from phonelog where Recordnum>"+Recordnum);
                ResultSet rs = query.getResultSet();

                // Process each row from query result
                while (rs.next()) {
                }
                JDBCHelper.close(rs);

                String plupdate="update Counters set value='"+Recordnum+"' where name='plposition'";
                submit.executeUpdate(plupdate);
                JDBCHelper.close(query);
            }
            catch (SQLException SQLe) {
                System.err.println(CurrentTime()+": "+SQLe.getMessage());
            }

                JDBCHelper.close(conn);

                System.out.println (CurrentTime()+": "+"Disconnected");
        }
    }

3 个答案:

答案 0 :(得分:1)

Java将创建对象和内存,直到它接近-Xmx最大堆大小设置,然后它将运行垃圾收集以释放空间。您应该使用-Xmx设置启动以控制JVM可以使用的内存量。您还应该知道,Connector / J JDBC驱动程序默认情况下会将整个结果缓存在内存中。

答案 1 :(得分:0)

  

如果我使用jconsole执行垃圾收集,则堆内存使用率会下降

然后它似乎不是泄漏;也许你可以使用-Xmx标志启动你的JVM以限制最大值。分配给JVM的内存量。这可能会更频繁地触发GC。

或者也许在你的循环中执行一个完整的GC:System.gc() - 通常不推荐,但是如果您的小应用程序可能会这样做。

答案 2 :(得分:0)

虽然我看到的一些内容是释放资源等待垃圾收集,但事实证明它主要是JDBC连接。重复打开和关闭连接会造成内存泄漏。我切换了代码,以便它只使用一个连接,而jconsole现在没有显示内存泄漏的迹象。应该给予 user1443778 以建议我只需要一个连接。 PreparedStatments建议也很好,因为我重写了代码以使用它们。

还要感谢您使用ConnectionPool的建议。这是一个很好的建议,但在我们使用Tomcat或JBOSS转移到VPS之前,我可能不会理会这一点。