0

私のクエリは、各行に 12 列の 31,000 の結果を返し、各行には約 8,000 文字 (行あたり 8KB) が含まれます。これが私が処理した方法です:

public List<MyTableObj> getRecords(Connection con) {
    List<MyTableObj> list = new ArrayList<MyTableObj>();
    String sql = "my query..."; 

    ResultSet rs = null;
    Statement st = null;

    con.setAutoCommit(false);
    st = con.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
    st.setFetchSize(50);
    rs = st.executeQuery(sql);

    try {
        System.out.println("Before MemoryFreeSize = " + (double)Runtime.getRuntime().freeMemory() / 1024 / 1024 + " MB");

        while ( rs.next() ) {
            MyTableObjitem item = new MyTableObj();
            item.setColumn1( rs.getString("column1") );
            ... ...
            item.setColumn12( rs.getString("column12") );

            list.add( item );
        } // end loop

        // try to release some memory, but it's not working at all
        if ( st != null ) st.close();
        if ( rs != null ) rs.close();
        st = null; rs = null;
    }
    catch ( Exception e ) { //do something }
    System.out.println("After MemoryFreeSize = " + (double)Runtime.getRuntime().freeMemory() / 1024 / 1024 + " MB");

    return list;
} // end getRecords

各行が 8kb のメモリを必要とする場合、31k は 242mb のメモリを必要とします。クエリ結果のループが終了した後、残りのメモリは 142 MB しかなく、他のプロセスの残りを完了するのに十分ではありません。

多くの解決策を検索し、ヒープ メモリを 512mb に設定しようとしました。-Xmx512m -Xms512mまた、フェッチ サイズも設定しましたsetFetchSize(50)

ResultSet がメモリを占有しすぎていると思われます。結果はクライアント側のキャッチに格納される可能性があります。ただし、いくつかのオブジェクト (st.close()およびrs.close()) をクリアした後、手動でガベージ コレクターを呼び出してもSystem.gc()、ループ後の空きメモリは増加しません (なぜですか?)。

データベースの設計を変更することはできず、すべてのクエリ結果が必要であると仮定しましょう。処理後にメモリを解放するにはどうすればよいですか?

PS: また、 を使用せずResultSet.getString()にハードコード文字列に置き換えようとしましたが、ループした後、450MB の空きメモリが得られました。

私がそうするなら、私はそれを見つけました:

// + counter to make the value different for each row, for testing purpose
item.setColumn1( "Constant String from Column1" + counter );
... ...
item.setColumn12( "Constant String from Column12" + counter );
counter++;

約60MBのメモリしか使用しませんでした。しかし、もしそうなら:

item.setColumn1( rs.getString("column1") );
... ...
item.setColumn12( rs.getString("column12") );

最大380MBのメモリを使用しました。

私はすでにrs.close();rs = null; //rs is Result instanceを実行しましたが、これは役に立たないようです。これら 2 つのアプローチでメモリ使用量が大きく異なるのはなぜですか? どちらのアプローチでも、String のみを渡しました。

4

3 に答える 3

0

同時にメモリに取得するすべてのデータが必要な場合 (したがって、チャンクで処理することはできません)、十分なメモリが必要になります。1Gのメモリで試してみてください。

System.gc() の呼び出しを忘れてください。それは役に立ちません (OutOfMemoryException がスローされる前に呼び出されます)。

また、接続を閉じていないことにも気付きました。おそらくそれも行う必要があります (まだ接続プールがない場合は、設定してください)。

もちろん、プロファイラーを使用して、メモリが実際にどこに行くのかを確認できます。あなたが今していることは純粋な当て推量です。

于 2013-10-03T08:08:47.563 に答える
0

クエリを絞り込み、より具体的に取得して、必要に応じてクエリに制限を追加して、Java が大きすぎる結果を処理できないようにする必要があります。

于 2013-10-03T07:46:17.940 に答える