考虑创建5-6个线程的应用程序,每个线程在周期中为5mb的页面大小分配MappedByteBuffer。
MappedByteBuffer b = ch.map(FileChannel.MapMode.READ_ONLY, r, 1024*1024*5);当应用程序处理大文件时,oom迟早会抛出。
java.io.IOException: Map failed at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:758)
Caused by: java.lang.OutOfMemoryError: Map failed
at sun.nio.ch.FileChannelImpl.map0(Native Method)
at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:755)根据规范,一旦MappedBuffer成为GC本身,就应该立即处理直接内存。看起来问题是,MappedBuffer的GC-s太晚了,然后直接内存就完成了。
如何避免这种情况?可能会说MappedBuffer来隐式处置或使用某种类型的MappedBuffer池
发布于 2011-12-19 06:10:20
您可以通过直接清理映射的字节缓冲区来避免触发GC。
public static void clean(ByteBuffer bb) {
if(bb == null) return;
Cleaner cleaner = ((DirectBuffer) bb).cleaner();
if(cleaner != null) cleaner.clean();
}如果您在丢弃之前调用此函数,则不会耗尽虚拟内存。
也许您可以考虑创建更大的ByteBuffers (除非您有大量的文件)创建MappedByteBuffer是不免费的(在某些机器上需要大约50微秒)
发布于 2011-12-19 01:03:42
错误消息显示"map failed",而不是"heap space“或"permgen space”。这意味着JVM没有足够的地址空间可用。
请参阅Sun数据库中的this bug,以及this question。
第一个链接提供了一个变通方法(ewww),它接近于第二个链接所说的内容:
try {
buffer = channel.map(READ_ONLY, ofs, n);
} catch (java.io.IOException e) {
System.gc();
System.runFinalization();
buffer = channel.map(READ_ONLY, ofs, n);
}发布于 2011-12-19 00:47:09
也许将这些MappedBuffers放入池中的WeakHashMap会起作用。
但在你猜测根本原因之前,我建议将你的应用程序连接到Visual VM 1.3.3,并安装所有的插件,这样你就可以确切地看到是什么导致了面向对象模型错误。你假设这些MappedBuffers正在做这件事,但是它们只有5-6个线程,每个线程只有5MB -总共25-30MB。
有数据比猜测更好。Visual VM将为您获取它。
https://stackoverflow.com/questions/8553158
复制相似问题