【问题标题】:How do I fix "java.lang.OutOfMemoryError at sun.misc.Unsafe.allocateMemory(Native Method)"?如何修复“java.lang.OutOfMemoryError at sun.misc.Unsafe.allocateMemory(Native Method)”?
【发布时间】:2010-01-25 01:48:35
【问题描述】:

我正在制作一个使用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)

我的虚拟机选项是:

-Djava.library.path=lib -Xms1024M -Xmx1024M -XX:PermSize=256M -XX:MaxPermSize=256M

程序在开始时会加载一些大图像(1024 x 768 分辨率)。

任何解决此问题的帮助将不胜感激。

【问题讨论】:

    标签: java image memory graphics


    【解决方案1】:

    OutOfMemoryError 只是表示 JVM 内存不足。堆栈跟踪的第一行在这里并不真正相关,因为它只是“巧合”正是那里 JVM开始耗尽内存,所有垃圾收集都是徒劳的。

    基本上有两种解决方案:

    1. 给 JVM 更多内存。
    2. 修复内存泄漏和/或在代码中分配更少的内存(即提高代码的内存效率,不要占用内存昂贵的资源,如大的byte[] 太久等等)。

    第 1 点很容易做到,但如果代码中明显存在内存泄漏,则不一定是解决方案。第 2 点最好在Java profiler 的帮助下确定。

    【讨论】:

      【解决方案2】:

      根据具体情况,它可能是 2005 年以来出现的 JVM 错误的表现。

      如果您查看 java.nio.DirectByteBuffer 类中的代码,您会看到它创建了一个线程来释放所请求的内存。如果你的程序使用了这个类的大量实例(例如间接通过 IOUtils),即使你有足够的内存,你也可能会得到 OOME。只是线程没有机会释放内存。

      这是一个讨厌的。

      http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6296278

      【讨论】:

        【解决方案3】:

        发现了问题,我正在尝试将 6144x6144 PNG 加载到我的程序中。

        将图像重新调整为 256x256 TGA 后,程序可以正常加载而不会出现错误。

        【讨论】:

          【解决方案4】:

          @BalusC 关于原因和解决方案大多是正确的。

          但是,OOM​​E 的直接原因可能是在某些计算机上,JVM 无法将堆扩展到 -XX 选项指定的大小。例如,如果请求的内存量超过剩余可用物理内存+交换空间,操作系统将拒绝 JVM 扩展堆的请求。这或许可以解释为什么应用程序可以在某些机器上运行,而在其他机器上却不行……使用相同的 VM 选项,以及(我猜)处理器架构和 JVM 版本。

          如果这是问题所在,OP 将需要添加更多物理内存或增加系统的交换空间。

          要扩展@BalusC 的第二个解决方案,OP 可能需要更改应用程序,以便它不会在启动时急切加载图像。相反,它可以延迟加载它们,并使用带有弱引用的缓存来确保 GC 可以在内存紧张时丢弃它们。 但是,如果预加载所有图像至关重要,那么 OP 就别无选择,只能弄清楚如何给 JVM 更大的堆;见上文。

          【讨论】:

            【解决方案5】:

            当您收到此特定异常时,堆栈跟踪以Unsafe.allocateMemory(Native Method) 结尾,这意味着操作系统拒绝了分配更多内存的请求;表明您已达到 JVM 对 Java 堆内存的限制的异常将具有不同的堆栈跟踪。

            因此可用的修复方法是:在应用程序的某处节省一些内存,购买更多物理 RAM(或更大的驱动器,以便为交换文件留出更多空间),或者检查您是否可以配置操作系统以允许更多内存分配,例如通过增加交换空间。

            如果发生这种情况时您分配的是常规 Java 对象(而不是本机内存缓冲区或非常大的原语数组),我只建议您重写代码以节省内存,或者使用具有更多 RAM 的机器;由于垃圾收集器需要遍历堆上的每个可访问对象以将它们标记为活动,这意味着您通常不会引用的对象仍然必须由 JVM 定期提取到内存中......所以使用大量交换对于小型 Java 对象会变得非常昂贵。

            对于许多大图像的情况,我建议仅使用软引用来保留您认为可能再次需要的图像,这允许 JVM 在需要内存时将它们从内存中删除,但鼓励它保留它们如果可行,在内存中,以避免定期重新加载它们的性能问题。

            【讨论】:

              猜你喜欢
              • 2015-03-11
              • 1970-01-01
              • 1970-01-01
              • 2017-04-18
              • 2018-07-04
              • 2012-01-09
              • 2023-03-21
              • 2018-08-27
              • 1970-01-01
              相关资源
              最近更新 更多