OutOfMemoryError on overprovisioned heap
Why am I getting the OutOfMemoryError when allocating a data structure that should happily fit within the heap I have provided for the JVM? This was a question I recently faced.
Indeed, when looking at what the developer was trying to accomplish and triple-checking the heap size given to the JVM via the -Xmx parameter, it indeed seemed that something shady was going on.
30 minutes later we understood the situation and solved the mystery. But it was indeed not obvious at the first place, so I thought it might save someone a day if I described the underlying problem in more details.
As always, the best way to understand a problem is via a hands-on example. I have constructed a small synthetic test case:
package eu.plumbr.demo; class ArraySize { public static void main(String... args) { int[] array = new int[1024*1024*1024]; } }
The code is simple – all it tries to do is to allocate an array with one billion elements. Now, considering that java int primitives require 4 bytes, one might think that running the code with 6g heap would run just fine. After all, those billion integers should consume only 4g memory. So why do I see the following when I execute the code?
My Precious:bin me$ java –Xms6g –Xmx6g eu.plumbr.demo.ArraySize Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at eu.plumbr.demo.ArraySize.main(ArraySize.java:6)
Before just tossing in even more heap (as a matter of fact, with –Xmx7g the example above runs just fine), let us try to understand why our expectation was wrong.
First – the int primitives in java do indeed require 4 bytes. So it is not like our JVM implementation has gone crazy over night. And I can assure you that the math is also correct – 1024*1024*1024 int primitives indeed would require 4,294,967,296 bytes or 4 gigabytes.
To understand what is happening, lets run the very same case and turn on garbage collection logging by specifying –XX:+PrintGCDetails:
My Precious:bin me$ java –Xms6g -Xmx6g -XX:+PrintGCDetails eu.plumbr.demo.ArraySize -- cut for brevity -- Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at eu.plumbr.demo.ArraySize.main(ArraySize.java:6) Heap PSYoungGen total 1835008K, used 125829K [0x0000000780000000, 0x0000000800000000, 0x0000000800000000) eden space 1572864K, 8% used [0x0000000780000000,0x0000000787ae15a8,0x00000007e0000000) from space 262144K, 0% used [0x00000007e0000000,0x00000007e0000000,0x00000007f0000000) to space 262144K, 0% used [0x00000007f0000000,0x00000007f0000000,0x0000000800000000) ParOldGen total 4194304K, used 229K [0x0000000680000000, 0x0000000780000000, 0x0000000780000000) object space 4194304K, 0% used [0x0000000680000000,0x0000000680039608,0x0000000780000000) PSPermGen total 21504K, used 2589K [0x000000067ae00000, 0x000000067c300000, 0x0000000680000000) object space 21504K, 12% used [0x000000067ae00000,0x000000067b087668,0x000000067c300000)
The answers are now staring right into our eyes: even though we have plenty of total heap available, no individual area in the heap is large enough to hold 4g of objects. Our 6g heap is divided into four separate regions, sized like this:
- Eden 1,536M
- Survivor spaces (from and to) 256M each
- OldGen 4,096M
Now, bearing in mind that object allocations must fit into a single region we indeed can see that the application stands no chance – there is just not enough room in any of our heap regions to accommodate this single 4g allocation.
So – is our only hope now to increase heap further? Even if we already have over-provisioned by nearly 50% – handing 6g of heap to a data structure which should fit into 4g? Not so fast – there is an alternative solution available. You can set the size of the different areas in memory. It is not as straightforward and user-friendly as one might expect, but two small modifications of the startup configuration will do the trick. When launching the same code with just two extra options:
My Precious:bin me$ java -Xms6g -Xmx6g -XX:NewSize=5g -XX:SurvivorRatio=10 eu.plumbr.demo.ArraySize
then the program does its job and no OutOfMemoryError is being thrown. Adding -XX:+PrintGCDetails to the startup also explains it:
Heap PSYoungGen total 4806144K, used 4369080K [0x00000006c0000000, 0x0000000800000000, 0x0000000800000000) eden space 4369408K, 99% used [0x00000006c0000000,0x00000007caaae228,0x00000007cab00000) from space 436736K, 0% used [0x00000007e5580000,0x00000007e5580000,0x0000000800000000) to space 436736K, 0% used [0x00000007cab00000,0x00000007cab00000,0x00000007e5580000) ParOldGen total 1048576K, used 0K [0x0000000680000000, 0x00000006c0000000, 0x00000006c0000000) object space 1048576K, 0% used [0x0000000680000000,0x0000000680000000,0x00000006c0000000) PSPermGen total 21504K, used 2563K [0x000000067ae00000, 0x000000067c300000, 0x0000000680000000) object space 21504K, 11% used [0x000000067ae00000,0x000000067b080c90,0x000000067c300000)
We see that the sizes of regions are now indeed what we asked for:
- Young size int total (eden + two survivor spaces) is 5g, as specified by our -XX:NewSize=5g parameter
- Eden is 10x larger than survivor, as we specified with the -XX:SurvivorRatio=10 parameter.
Note that in our case, both of the parameters were necessary. Specifying just the -XX:NewSize=5g would still split it between eden and survivors in a way where no individual area can hold the required 4g.
Hopefully reading this explanation will save you a day of debugging in the future. Or help you avoid over-provisioning the resources.
相关推荐
"Java.lang.OutOfMemoryError: Java heap space 解决方法" Java.lang.OutOfMemoryError: Java heap space 是 Java 中的一个常见错误,它发生时,Java 虚拟机 (JVM) 无法分配对象,因为堆空间不足。下面是解决该问题...
### Java 错误处理:java.lang.OutOfMemoryError: Java heap space 在Java应用程序开发过程中,经常遇到的一个问题就是内存溢出错误,特别是在处理大量数据或长时间运行的应用时。其中,“java.lang....
### Myeclipse下java.lang.OutOfMemoryError: Java heap space的解决方案 在使用Myeclipse进行Java开发时,可能会遇到`java.lang.OutOfMemoryError: Java heap space`这个错误提示。这种异常通常发生在应用程序占用...
java虚拟机OutOfMemoryError:Java heap space堆dump文件,可以直接用来分析。
Java程序在运行过程中可能会遇到各种异常,其中"nested exception is java.lang.OutOfMemoryError: Java heap space"是一个常见的问题,通常发生在程序试图分配超过堆内存限制的空间时。这个错误表明Java虚拟机(JVM...
### 编译时出现java.lang.OutOfMemoryError Java heap space异常 #### 一、问题概述 在进行Java项目编译的过程中,可能会遇到`java.lang.OutOfMemoryError: Java heap space`这种异常。这类异常通常表明Java虚拟机...
### Java.lang.OutOfMemoryError:Java Heap Space 错误及处理办法 在Java应用程序开发与维护过程中,经常会遇到`java.lang.OutOfMemoryError: Java heap space`这一异常情况。该异常通常表明Java虚拟机(JVM)的堆...
在Java程序中,`java.lang.OutOfMemoryError: Java heap space` 是一个常见的错误,意味着程序在运行过程中耗尽了JVM分配的堆内存。这个错误通常发生在创建大量对象或者单个对象占用过多内存时。 一、问题描述与...
java.lang.OutOfMemoryError: Java heap space 解决方法
在Tomcat中java.lang.OutOfMemoryError: Java heap space异常处理: 1. Heap size JVM堆的设置是指Java程序运行过程中JVM可以调配使用的内存空间的设置。 2. JVM在启动的时候会自动设置Heap size的值,其初始空间...
当应用程序创建大量对象,且这些对象生命周期较长,或者无法及时释放时,可能会导致堆内存溢出,表现为`java.lang.OutOfMemoryError: Java heap space`。为了解决这个问题,可以通过`-Xms`和`-Xmx`参数来设置堆的...
- **错误日志**:`java.lang.OutOfMemoryError: Java heap space` 和 `java.lang.OutOfMemoryError: GC overhead limit exceeded` - **原因**:创建大量对象或者内存泄露可能导致Java堆空间不足。例如,大数据加载...
当程序创建的对象过多或单个对象占用内存过大时,如果没有足够的空闲内存来分配新对象,JVM就会抛出“OutOfMemoryError: Java heap space”错误。这可能是由于以下原因造成的: 1. **初始堆大小设置不当**:默认...
Java开发过程中,遇到`OutOfMemoryError`是一种常见的挑战,它表明程序在运行时耗尽了内存资源。MAT(Memory Analyzer Tool)是IBM提供的一款强大的Java内存分析工具,它专为解决此类问题而设计,帮助开发者深入理解...
当程序创建新的对象并分配给堆时,如果堆空间不足,就会抛出`OutOfMemoryError: Java heap space`异常。Java应用程序可以通过设置JVM的启动参数来控制堆的大小,例如`-Xms`和`-Xmx`分别用于设置初始堆大小和最大堆...
### 内存溢出解决 #### 背景与概念 在Java开发中,内存管理是确保应用程序稳定运行的关键因素之一。当程序运行时分配给它的内存空间不足以支撑其正常运行时,就会出现“内存溢出”(Out of Memory Error,简称OOM...
Java异常解决之OutOfMemoryError Java 中的 OutOfMemoryError 异常是指 Java 虚拟机在运行时无法申请到足够的内存空间,导致程序崩溃的错误。该错误可以发生在 Java 堆、虚拟机栈、本地方法栈和直接内存等几个运行...
Exception in thread http-nio-8080-exec-1027 java.lang.OutOfMemoryError: Java heap space Exception in thread http-nio-8080-exec-1031 java.lang.OutOfMemoryError: Java heap space 看线程名称应该是tomcat的...