Search code examples
javastringbuffer

OutOfMemoryError vs NegativeArraySizeException


When i initialize the StringBuffer constructor with Integer.MAX_VALUE it throws OutOfMemoryError and when i add 16 to it it throws NegativeArraySizeException

  public class Test {
        public static void main(String[] arg) {
            StringBuffer sb = new StringBuffer(Integer.MAX_VALUE + 16);
            sb.append("A");
        }
    }

Can some one help me understand this behavior?


Solution

  • You have actually asked two entirely different questions here, so they must be addressed separately.

    1. Why does new StringBuffer(Integer.MAX_VALUE) throw an OutOfMemoryError?

    The StringBuffer constructor tries to instantiate an array of char, whose size is the value that you pass. So you're implicitly trying to instantiate an array of size Integer.MAX_VALUE. There are two reasons why you might get an OutOfMemoryError from instantiating an array.

    The first reason is that you genuinely don't have enough heap space. Without knowing what else is going on in your program, or what your heap settings are, it's impossible for me to tell whether that might be happening for you. But you can choose the maximum heap size for your JVM when you start it up, with the -Xmx option. Obviously, you'd need to set it to several gigabytes to get this to work (for example -Xmx8g), assuming your computer has enough RAM.

    The second reason for an OutOfMemoryError when instantiating an array is that you've exceeded the maximum array size. That's definitely happening here. The maximum array size is not defined by the Java Language Specification, and it varies from JVM to JVM. In most modern JVMs, the maximum array size is Integer.MAX_VALUE - 2, but there are JVMs in which the maximum is Integer.MAX_VALUE - 5 or Integer.MAX_VALUE - 8. In any case, Integer.MAX_VALUE is over the limit for sure.

    2. Why does new StringBuffer(Integer.MAX_VALUE + 16) throw a NegativeArraySizeException?

    This is to do with integer arithmetic in Java. Any int value has to be between Integer.MIN_VALUE and Integer.MAX_VALUE. Also, when you add two int values, the answer is guaranteed by the Java Language Specification to be an int. Therefore, when you evaluateInteger.MAX_VALUE + 16`, you're not going to get the mathematically correct answer. In fact, what Java does is to work mod 232. Another way of looking at it is that the JVM will add or subtract multiples of 232 to bring the answer within the correct range.

    That means that the value of Integer.MAX_VALUE + 16 will actually be numerically equal to Integer.MAX_VALUE + 16 -232, which is a large negative number. As I mentioned earlier, the StringBuffer constructor tries to instantiate an array whose size is the value that you pass. This attempt to instantiate an array of negative size gives you your NegativeArraySizeException.