即使没有内存,我会遇到java.lang.OutOfMemoryError吗?

Pac*_*ier 5 java memory jvm out-of-memory

我正在阅读Unveiling java.lang.Out OfMemoryError,我想知道我是否正确理解它.如果Java VM抛出一个,那是真的吗?

java.lang.OutOfMemoryError:请求的数组大小超过VM限制

这意味着VM已经拒绝创建数组,因为它超出了预定义的限制(超过了VM的类似限制),而不是因为我在堆空间中耗尽了内存?

我是否正确地说这java.lang.OutOfMemoryError: Requested array size exceeds VM limit并不表示缺乏记忆?

即使我到处都有无限的内存,如果Java VM 不喜欢我创建n大小数组的请求,它仍然会抛出一个?java.lang.OutOfMemoryError: Requested array size exceeds VM limit

Tom*_*icz 9

使用HotSpot VM引用Java SE 6故障排除指南

3.1.3详细消息:(Requested array size exceeds VM limit内联粗体是我的):

详细消息Requested array size exceeds VM limit表明应用程序(或该应用程序使用的API)尝试分配大于堆大小的数组.例如,如果应用程序尝试分配512MB的数组但最大堆大小为256MB,OutOfMemoryError则会抛出原因Requested array size exceeds VM limit.在大多数情况下,问题是配置问题(堆大小太小),或导致应用程序尝试创建大型数组的错误,例如,当使用计算的算法计算数组中的元素数量时尺寸不正确.


更新:@Pacerier鼓励我做了一些快速测试.我写了一个示例程序:

public class VmLimitTest {

    public static final int SIZE = 2;

    public static void main(String[] args) throws InterruptedException {
        while(true) {
            byte[] a = new byte[SIZE * 1024 * 1024];
            TimeUnit.MILLISECONDS.sleep(10);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

并使用以下JVM选项运行它:

-Xms192m -Xmx192m -XX:NewRatio=2 -XX:SurvivorRatio=6 -XX:+PrintGCDetails
Run Code Online (Sandbox Code Playgroud)

这就是他们的意思:

  • 整堆是192 MiB(-Xms192m -Xmx192m)
  • 年轻一代(伊甸园+幸存者)空间是64 MiB,老一代是128 MiB(-XX:NewRatio=2)
  • 每个幸存者空间(两个中)是8 MiB,所以48 MiB留给伊甸园(1:6比例-XX:SurvivorRatio=6)

在测试时我发现了以下内容:

  • 如果新创建的数组可以适合eden(小于48 MiB),程序运行正常
  • 令人惊讶的是,当阵列大小超过伊甸园大小,但可以适应伊甸园和一个幸存者空间(48到56 MiB之间)时,JVM可以在伊甸园和幸存者(重叠两个区域)上分配单个对象.整齐!
  • 一旦阵列大小超过eden +单个幸存者(超过56 MiB),新创建的对象将直接放置在旧一代中,绕过伊甸园和幸存者空间.这也意味着突然完全GC一直在执行 - 非常糟糕!
  • 我可以很容易地分配127 MiB的数据但是试图分配129 MiB 将会抛出OutOfMemoryError: Java heap space

这是底线 - 您无法创建大于旧代的对象.试图这样做会导致OutOfMemoryError: Java heap space错误.那么我们Requested array size exceeds VM limit什么时候可以期待可怕的?

我尝试使用更大的对象运行相同的程序.达到我切换到的阵列长度限制long[],可以很容易地达到7 GiB.声明了最大堆的128 MiB,JVM仍在抛出OutOfMemoryError: Java heap space(!)我设法OutOfMemoryError: Requested array size exceeds VM limit在单个对象中尝试分配8 GiB时触发错误.我在具有3 GiB物理内存和1 GiB交换的32位Linux计算机上进行了测试.

话虽这么说你应该永远不会遇到这个错误.文档似乎不准确/过时,但在一个结论中确实如此:这可能是一个错误,因为创建如此庞大的数组是非常罕见的.

  • http://java.sys-con.com/node/1229281声明VM可能拒绝创建数组并抛出"OOM:请求的数组大小超过VM限制",即使堆中有足够的内存来创建该数组.你是说这是错误的(因为如果堆中有足够的内存,VM**必须不这样做)? (2认同)