gpt4 book ai didi

java - Linux 上的 FileChannel.write 会产生大量垃圾,但在 Mac 上不会

转载 作者:塔克拉玛干 更新时间:2023-11-02 19:36:16 24 4
gpt4 key购买 nike

我试图限制我的日志库产生的垃圾量,所以我编写了一个测试来显示 FileChannel.write 创建了多少内存。下面的代码在我的 Mac 上分配了零内存,但在我的 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 池。所以没有真正的内存泄漏,只是浪费。 感叹

关于java - Linux 上的 FileChannel.write 会产生大量垃圾,但在 Mac 上不会,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7474766/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com