我正在创建一个使用Slick库来加载图像的Java应用程序。但是,在某些计算机上,我在尝试运行程序时遇到此错误:
Exception in thread "main" java.lang.OutOfMemoryError
at sun.misc.Unsafe.allocateMemory(Native Method)
at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:99)
at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:288)
at org.lwjgl.BufferUtils.createByteBuffer(BufferUtils.java:60)
at org.newdawn.slick.opengl.PNGImageData.loadImage(PNGImageData.java:692)
at org.newdawn.slick.opengl.CompositeImageData.loadImage(CompositeImageData.java:62)
at org.newdawn.slick.opengl.CompositeImageData.loadImage(CompositeImageData.java:43)
我的VM选项是:
-Djava.library.path=lib -Xms1024M -Xmx1024M -XX:PermSize=256M -XX:MaxPermSize=256M
程序在开头加载一些大图像(1024 x 768分辨率)。
非常感谢任何帮助解决这个问题。
答案 0 :(得分:4)
OutOfMemoryError
只表示JVM内存不足。堆栈跟踪的第一行在这里并不真正相关,因为它只是“巧合”,正是那里,其中JVM开始耗尽内存,所有垃圾收集都是徒劳的。
基本上有两种解决方案:
byte[]
等等。)第1点很容易做到,但如果代码中存在明显的内存泄漏,则不一定是解决方案。第2点最好在Java profiler的帮助下确定。
答案 1 :(得分:2)
根据具体情况,它可能是自2005年以来出现的JVM错误的一种表现形式。
如果查看java.nio.DirectByteBuffer类中的代码,您将看到它创建了一个线程来释放请求的内存。如果您编程使用此类的大量实例(例如通过IOUtils间接),即使您有足够的内存,也可能获得OOME。只是线程没有机会释放内存。
这是一个讨厌的人。
答案 2 :(得分:1)
发现问题,我试图将6144x6144 PNG加载到我的程序中。
将图像重新调整为256x256 TGA后,程序可以正常加载而不会出现错误。
答案 3 :(得分:0)
@BalusC对于原因和解决方案大多是正确的。
但是,OOME的直接原因可能是某些计算机上的JVM无法将堆扩展到-XX选项指定的大小。例如,如果请求的内存量超过剩余的可用物理内存+交换空间,操作系统将拒绝JVM扩展堆的请求。这可能解释了为什么应用程序可以在某些机器上运行而不是其他机器......具有相同的VM选项,以及(我猜)处理器体系结构和JVM版本。
如果这是问题,OP将需要添加更多物理内存或增加系统的交换空间。
为了扩展@BalusC的第二个解决方案,OP可能需要更改应用程序,以便它不会在启动时急切地加载图像。相反,它可能会延迟加载它们,并使用带有弱引用的缓存来确保GC在内存紧张时可以丢弃它们。 但是,如果所有图像都预先加载是至关重要的,那么OP别无选择,只能弄清楚如何为JVM提供更大的堆;见上文。
答案 4 :(得分:0)
当您收到此特定异常时,堆栈跟踪以Unsafe.allocateMemory(Native Method)
结尾,这意味着OS拒绝了分配更多内存的请求。表示您已达到JVM对Java堆内存的限制的异常将具有不同的堆栈跟踪。
因此,可用的修补程序是:在应用程序中的某个位置保存一些内存,购买更多的物理RAM(或更大的驱动器,以为交换文件留出更多空间),或者检查是否可以配置操作系统以允许更多的内存分配,例如通过增加交换空间。
如果发生这种情况时,如果要分配常规的Java对象(而不是本机内存缓冲区或大量的原语数组),我只建议重写代码以节省内存,或者使用更多RAM的机器。由于垃圾收集器需要遍历堆上的每个可访问对象以将它们标记为活动对象,因此这意味着您仍然经常需要将未引用的对象由JVM定期提取到内存中,因此需要进行大量交换用于小型Java对象的价格相当昂贵。
对于许多大图像,我建议仅使用软引用来保留您认为可能需要的图像,这允许JVM在需要内存时将其从内存中删除,但鼓励它保留它们如果可行,则将其存储在内存中,以避免定期重新加载它们的性能问题。