3

ログ ライブラリによって生成されるガベージの量を制限しようとしているので、FileChannel.write が作成しているメモリの量を示すテストをコーディングしました。以下のコードは、私の Mac に ZERO メモリを割り当てますが、Linux ボックス (Ubuntu 10.04.1 LTS) に大量のゴミを作成し、GC をトリガーします。FileChannel は高速で軽量であると想定されています。これが Linux で改善された JRE バージョンはありますか?

    File file = new File("fileChannelTest.log");
    FileOutputStream fos = new FileOutputStream(file);
    FileChannel fileChannel = fos.getChannel();
    ByteBuffer bb = ByteBuffer.wrap("This is a log line to test!\n".getBytes());
    bb.mark();
    long freeMemory = Runtime.getRuntime().freeMemory();
    for (int i = 0; i < 1000000; i++) {
        bb.reset();
        fileChannel.write(bb);
    }
    System.out.println("Memory allocated: " + (freeMemory - Runtime.getRuntime().freeMemory()));

私のJREの詳細は以下の通りです:

java version "1.6.0_19"
Java(TM) SE Runtime Environment (build 1.6.0_19-b04)
Java HotSpot(TM) 64-Bit Server VM (build 16.2-b04, mixed mode)

更新:

java version "1.6.0_27"
Java(TM) SE Runtime Environment (build 1.6.0_27-b07)
Java HotSpot(TM) 64-Bit Server VM (build 20.2-b06, mixed mode)

そして、それはうまくいきました。:-|

これで、以前のバージョンの FileChannelImpl にはメモリ割り当ての問題があることがわかりました。

4

1 に答える 1

2

私はUbuntu 10.04を使用していますが、あなたの観察を確認できます。私のJDKは次のとおりです。

    java version "1.6.0_20"
    OpenJDK Runtime Environment (IcedTea6 1.9.9) (6b20-1.9.9-0ubuntu1~10.04.2)
    OpenJDK 64-Bit Server VM (build 19.0-b09, mixed mode)

解決策は、配列に基づくDirectByteBufferではなく、を使用することです。HeapByteBuffer

私の記憶が正しければ、これは JDK 1.4 にさかのぼる非常に古い「機能」DirectByteBufferです。基本的に、これらの一時バッファーが JVM に残っていることがわかります。ChannelDirectByteBuffer

次のコードは私にとってはうまくいきます:

    File file = new File("fileChannelTest.log");
    FileOutputStream fos = new FileOutputStream(file);
    FileChannel fileChannel = fos.getChannel();

    ByteBuffer bb1 = ByteBuffer.wrap("This is a log line to test!\n".getBytes());

    ByteBuffer bb2 = ByteBuffer.allocateDirect(bb1.remaining());
    bb2.put(bb1).flip();

    bb2.mark();
    long freeMemory = Runtime.getRuntime().freeMemory();
    for (int i = 0; i < 1000000; i++) {
        bb2.reset();
        fileChannel.write(bb2);
    }
    System.out.println("Memory allocated: " + (freeMemory - Runtime.getRuntime().freeMemory()));

参考までに:のコピーをHeapByteBuffer取り込んでいます

    sun.nio.ch.IOUtil.write(FileDescriptor, ByteBuffer, long, NativeDispatcher, Object)

を使用しますsun.nio.ch.Util.getTemporaryDirectBuffer(int)DirectByteBufferこれにより、 s を使用してs のスレッドごとの小さなプールが実装されますSoftReference。そのため、実際のメモリ リークは発生せず、無駄になるだけです。はぁ

于 2011-09-19T18:38:10.290 に答える