OutOfMemoryError与NegativeArraySizeException

时间:2017-05-05 05:31:41

标签: java stringbuffer

当我使用 Integer.MAX_VALUE 初始化StringBuffer构造函数时,它会抛出OutOfMemoryError,当我向它添加16时,它会抛出NegativeArraySizeException

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

有人可以帮我理解这种行为吗?

3 个答案:

答案 0 :(得分:1)

您实际上已经在这里提出了两个完全不同的问题,因此必须单独解决。

<强> 1。为什么new StringBuffer(Integer.MAX_VALUE)会抛出OutOfMemoryError

StringBuffer构造函数尝试实例化char数组,其大小是您传递的值。因此,您隐式尝试实例化大小为Integer.MAX_VALUE的数组。有两个原因可能导致OutOfMemoryError实例化数组。

第一个原因是你真的没有足够的堆空间。如果不知道你的程序中还有什么,或者你的堆设置是什么,我就不可能告诉你这是否会发生。但是,您可以使用-Xmx选项在启动时为JVM选择最大堆大小。显然,假设您的计算机有足够的RAM,您需要将其设置为几千兆字节才能使其正常工作(例如-Xmx8g)。

实例化数组时OutOfMemoryError的第二个原因是您已超出最大数组大小。这肯定发生在这里。 Java语言规范未定义最大数组大小,它从JVM到JVM各不相同。在大多数现代JVM中,最大数组大小为Integer.MAX_VALUE - 2,但有些JVM的最大值为Integer.MAX_VALUE - 5Integer.MAX_VALUE - 8。无论如何,Integer.MAX_VALUE肯定超过了限制。

<强> 2。为什么new StringBuffer(Integer.MAX_VALUE + 16)会抛出NegativeArraySizeException

这与Java中的整数运算有关。任何int值必须介于Integer.MIN_VALUEInteger.MAX_VALUE之间。此外,当您添加两个int值时,Java语言规范保证答案为int. Therefore, when you evaluate Integer.MAX_VALUE + 16`,您将无法获得数学上正确的答案。事实上,Java所做的是工作mod 2 32 。查看它的另一种方法是JVM将加上或减去2 32 的倍数,以使答案在正确的范围内。

这意味着Integer.MAX_VALUE + 16的值实际上在数值上等于Integer.MAX_VALUE + 16 - 2 32 ,这是一个很大的负数。正如我之前提到的,StringBuffer构造函数尝试实例化一个数组,其大小是您传递的值。这种尝试实例化负数大小的数组会为您提供NegativeArraySizeException

答案 1 :(得分:0)

如果您将src添加到1,最终会得到Integer.MAX_VALUE。从这里开始,您应该知道添加Integer.MIN_VALUE时会发生什么:

16

<强>解释

Java 中的整数由32位表示,而最重要的一位(最左边的位)表示整数的符号(0 ==正数,1 ==否定)。

Integer.MAX_VALUE + 16 == Integer.MAX_VALUE + 1 + 15 == Integer.MIN_VALUE + 15 表示为:Integer.MAX_VALUE。添加01111111111111111111111111111111会将所有1翻转到1 s并将最左侧0翻到0,从而产生1这是一个负数,更具体10000000000000000000000000000000

答案 2 :(得分:0)

StringBuffer在其实现中使用字符数组来存储字符串。以下是其超类AbstractStringBuilder的构造函数,其中实际分配了数组:

AbstractStringBuilder(int capacity) {
    value = new char[capacity];
}

正如您所看到的,新的char[]数组将使用您传入的容量整数进行初始化.Java中字符数组的最大大小是堆大小的较小或{ {1}}。如果以下代码引发了错误,那么我的猜测就是你的堆内存不足了:

Integer.MAX_VALUE

假设堆有足够的空间,我本以为这会工作。但是,尝试分配StringBuffer sb = new StringBuffer(Integer.MAX_VALUE); 大小StringBuffer 无法工作,因为它会超过基础Integer.MAX_VALUE + 16数组的最大大小。