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

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

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

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

我是否正确地说java.lang.OutOfMemoryError: Requested array size exceeds VM limit并不表示内存不足?

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

使用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); } } } 

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

 -Xms192m -Xmx192m -XX:NewRatio=2 -XX:SurvivorRatio=6 -XX:+PrintGCDetails 

这就是他们的意思:

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

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

  • 如果新创建的数组可以适合eden(小于48 MiB),程序运行正常
  • 令人惊讶的是,当arrays大小超过eden大小,但可以适应伊甸园和一个幸存者空间(48到56 MiB之间)时,JVM可以在eden和幸存者(重叠两个区域)上分配单个对象。 整齐!
  • 一旦arrays大小超过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计算机上进行了测试。

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

它表示缺少堆内存。 其他区域可能有大量可用内存,但没有足够的堆内存来创建请求的对象(可能是数组(或)简单字符串)。 这是关于这个主题的好博客。