当我使用 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");
}
}
有人可以帮我理解这种行为吗?
答案 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 - 5
或Integer.MAX_VALUE - 8
。无论如何,Integer.MAX_VALUE
肯定超过了限制。
<强> 2。为什么new StringBuffer(Integer.MAX_VALUE + 16)
会抛出NegativeArraySizeException
?
这与Java中的整数运算有关。任何int
值必须介于Integer.MIN_VALUE
和Integer.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
数组的最大大小。