2011-10-31 37 views
3

我正在分配大量的字节缓冲区。在完成它们之后,我将所有引用都设置为null。这应该是释放字节缓冲区的“正确”方法?取消引用并让GC清理它?我也调用System.gc()来尝试并帮助它。什么阻止了我的ByteBuffer从释放?

无论如何,我创建了一堆缓冲区,尊重它们;但在“一段时间”后,我得到各种内存错误:java.lang.OutOfMemoryError:直接缓冲区内存

我可以增加MaxDirectMemorySize,但它只是延迟了上述错误。

我99%肯定我没有任何东西引用旧的ByteBuffers。有没有办法来检查这个来看看它还有一个ByteBuffer分配了什么?

+0

引用据称未引用的数据结构往往在集合类隐藏掉。其他地方包括听众和其他内部类的构造。我会先检查那些地方。 –

回答

1

您可以使用免费的Eclipse之类的工具,通过让它执行一些heapdump分析来查看保留字节缓冲区的内容。

我能想到的另一种方法是用其他方法来包装你的字节缓冲区,它有一个终结器方法。

此外,Systen.gc()不保证将执行终结器,您需要执行System.runFinalization()以增加可能性。

+0

你可以在http://www.eclipse.org/mat/获得MAT。 –

1

将引用设置为null是让垃圾回收器完成该对象的正确方法。还必须有其他一些悬而未决的参考。我发现寻找内存泄漏的最佳工具是YourKit。免费的替代品也非常好,是Visual VM from the JDK

请记住,slice()操作会创建一个引用第一个字节的新字节缓冲区。

0

这是旧版本Java的问题。在抛出OutOfMemoryError之前,最新版本的Java 6将调用System.gc()。如果你不想触发GC您可以

((DirectBuffer) buffer).cleaner().clean(); 

但是手动释放的甲骨文/ Sun JVM的直接内存,这是一个更好的办法来回收直接缓冲区自己这样做并非如此危急。 (创建直接ByteBuffers比较昂贵)

0

直接java.nio.ByteBuffer是(根据定义)存储在java堆空间之外。直到GC在堆上运行并释放它,它才会被释放。但是您可以想象堆使用率低的情况,因此它不需要GC,但非堆内存得到分配并且超出边界。

基于非常有趣的阅读: http://www.ibm.com/developerworks/library/j-nativememory-linux/

The pathological case would be that the native heap becomes full and one or more direct ByteBuffers are eligible for GC (and could be freed to make some space on the native heap), but the Java heap is mostly empty so GC doesn't occur.

相关问题