簡體   English   中英

Linux上的FileChannel.write會產生大量垃圾,但不會出現在Mac上

[英]FileChannel.write on Linux produces lots of garbage, but not on Mac

我試圖限制我的日志庫產生的垃圾量,所以我編寫了一個測試來向我展示FileChannel.write創建了多少內存。 下面的代碼在我的Mac上分配了ZERO內存,但是在我的Linux機箱(Ubuntu 10.04.1 LTS)上創建了大量的垃圾,觸發了GC。 FileChannels應該是快速和輕量級的。 是否有一個JRE版本在Linux上做得更好?

    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存在內存分配問題。

我在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:如果你沒有給一個Channel提供DirectByteBuffer ,那么就會分配一個臨時的DirectByteBuffer並在寫入之前復制內容。 您基本上看到這些臨時緩沖區在JVM中揮之不去。

以下代碼適用於我:

    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) 這反過來使用SoftReference實現了一個DirectByteBuffer的每個線程池。 所以沒有真正的內存泄漏, 只有浪費。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM