4

私は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. 

コードは遅延を伴うループで実行されています。現在、コードは間隔ごとに接続を開きます。接続を 1 つだけ開いてメソッドに渡す必要がありますか? いずれにせよ、なぜそれが漏れの原因になるのかわかりません。どんな助けでも大歓迎です。

コードの一部を次に示します。これにより、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");
        }
    }
4

3 に答える 3

1

Javaは、オブジェクトを作成し、-Xmxの最大ヒープサイズ設定に近づくまでメモリを増やします。その後、ガベージコレクションを実行して、スペースを解放します。JVMが使用できるメモリ量を制御するには、-Xmx設定で起動する必要があります。Connector / J JDBCドライバーは、デフォルトで結果全体をメモリーにバッファーすることにも注意してください。

于 2012-09-03T03:56:30.800 に答える
0

jconsole でガベージ コレクションを実行すると、ヒープ メモリの使用量が元に戻ります

それなら漏れではないようです。おそらく、-Xmx フラグを使用して JVM を起動し、最大値を制限できます。JVM に割り当てられたメモリの量。これにより、より頻繁に GC がトリガーされる可能性があります。

または、ループ内で完全な GC を実行することもできます: System.gc() -- 通常はまったく推奨されませんが、小さなアプリケーションの場合はうまくいくかもしれません。

于 2012-09-03T03:17:29.637 に答える
0

私が見たもののいくつかは、ガベージ コレクションを待っている解放されたリソースであることは事実でしたが、それはほとんどが JDBC 接続であることが判明しました。接続を繰り返し開いたり閉じたりすると、メモリ リークが発生していました。接続を 1 つだけ使用するようにコードを変更したところ、jconsole でメモリ リークの兆候は見られなくなりました。user1443778は、接続が 1 つだけ必要であると示唆したことを認めるべきです。私がそれらを使用するためにコードを書き直したので、PreparedStatmentsの提案も良かったです。

ConnectionPool を使用する提案もありがとうございます。これは良い提案ですが、Tomcat または JBOSS を使用して VPS に移行するまで、おそらく気にすることはありません。

于 2012-09-03T12:42:55.077 に答える