Я нахожусь на 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
для Channel
, тогда будет выделен временный 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)
.Это, в свою очередь, реализует небольшой пул на поток DirectByteBuffer
с использованием SoftReference
с.Таким образом, нет никакой реальной утечки памяти, а только растрата. Вздох