OutOfMemoryError 与 NegativeArraySizeException
OutOfMemoryError vs NegativeArraySizeException
当我使用 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");
}
}
有人可以帮助我理解这种行为吗?
如果您将 1
添加到 Integer.MAX_VALUE
,您将得到 Integer.MIN_VALUE
。从这里开始,您应该知道添加 16
:
时会发生什么
Integer.MAX_VALUE + 16 == Integer.MAX_VALUE + 1 + 15 == Integer.MIN_VALUE + 15
说明
Java 中的整数由 32 位表示,而最高有效位(最左边的位)表示 整数的符号(0 == 正,1 == 负)。
Integer.MAX_VALUE
表示为:01111111111111111111111111111111
。添加 1
会将所有 1
翻转为 0
,并将最左边的 0
翻转为 1
,结果是 10000000000000000000000000000000
,这是一个负数, 更具体 Integer.MIN_VALUE
.
A StringBuffer
在其实现中使用字符数组来存储字符串。这是它的超级 class、AbstractStringBuilder
的构造函数,其中实际分配了数组:
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
如您所见,新的 char[]
数组使用您传入的容量整数进行初始化。Java 中字符数组的最大大小是 更小的[=堆大小的 27=] 或 Integer.MAX_VALUE
。如果以下代码抛出错误,那么我的猜测是您的堆 运行 内存不足:
StringBuffer sb = new StringBuffer(Integer.MAX_VALUE);
假设堆有足够的 space,我本以为这会起作用。但是尝试分配大小为 Integer.MAX_VALUE + 16
的 StringBuffer
无法 工作,因为它会超过基础 char[]
数组的最大大小。
您在这里实际上问了两个完全不同的问题,因此必须分开解决。
1.为什么 new StringBuffer(Integer.MAX_VALUE)
抛出 OutOfMemoryError
?
StringBuffer
构造函数尝试实例化 char
的数组,其大小是您传递的值。因此,您正在隐式地尝试实例化一个大小为 Integer.MAX_VALUE
的数组。实例化数组可能会得到 OutOfMemoryError
的原因有两个。
第一个原因是您确实没有足够的堆space。在不知道您的程序中还发生了什么,或者您的堆设置是什么的情况下,我无法判断您是否正在发生这种情况。但是您可以在启动时使用 -Xmx
选项为您的 JVM 选择最大堆大小。显然,假设您的计算机有足够的 RAM,您需要将其设置为几千兆字节才能使其正常工作(例如 -Xmx8g
)。
实例化数组时出现 OutOfMemoryError
的第二个原因是您超出了最大数组大小。这肯定发生在这里。最大数组大小未由 Java 语言规范定义,并且因 JVM 的不同而不同。在大多数 modern 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所做的就是工作mod232。另一种看待它的方式是,JVM 将加上或减去 232 的倍数,以使答案在正确的范围内。
这意味着Integer.MAX_VALUE + 16
的值实际上在数值上等于Integer.MAX_VALUE + 16 -
232,这是一个很大的负数。正如我前面提到的,StringBuffer
构造函数尝试实例化一个数组,其大小是您传递的值。这种实例化负大小数组的尝试为您提供了 NegativeArraySizeException
.
当我使用 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");
}
}
有人可以帮助我理解这种行为吗?
如果您将 1
添加到 Integer.MAX_VALUE
,您将得到 Integer.MIN_VALUE
。从这里开始,您应该知道添加 16
:
Integer.MAX_VALUE + 16 == Integer.MAX_VALUE + 1 + 15 == Integer.MIN_VALUE + 15
说明
Java 中的整数由 32 位表示,而最高有效位(最左边的位)表示 整数的符号(0 == 正,1 == 负)。
Integer.MAX_VALUE
表示为:01111111111111111111111111111111
。添加 1
会将所有 1
翻转为 0
,并将最左边的 0
翻转为 1
,结果是 10000000000000000000000000000000
,这是一个负数, 更具体 Integer.MIN_VALUE
.
A StringBuffer
在其实现中使用字符数组来存储字符串。这是它的超级 class、AbstractStringBuilder
的构造函数,其中实际分配了数组:
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
如您所见,新的 char[]
数组使用您传入的容量整数进行初始化。Java 中字符数组的最大大小是 更小的[=堆大小的 27=] 或 Integer.MAX_VALUE
。如果以下代码抛出错误,那么我的猜测是您的堆 运行 内存不足:
StringBuffer sb = new StringBuffer(Integer.MAX_VALUE);
假设堆有足够的 space,我本以为这会起作用。但是尝试分配大小为 Integer.MAX_VALUE + 16
的 StringBuffer
无法 工作,因为它会超过基础 char[]
数组的最大大小。
您在这里实际上问了两个完全不同的问题,因此必须分开解决。
1.为什么 new StringBuffer(Integer.MAX_VALUE)
抛出 OutOfMemoryError
?
StringBuffer
构造函数尝试实例化 char
的数组,其大小是您传递的值。因此,您正在隐式地尝试实例化一个大小为 Integer.MAX_VALUE
的数组。实例化数组可能会得到 OutOfMemoryError
的原因有两个。
第一个原因是您确实没有足够的堆space。在不知道您的程序中还发生了什么,或者您的堆设置是什么的情况下,我无法判断您是否正在发生这种情况。但是您可以在启动时使用 -Xmx
选项为您的 JVM 选择最大堆大小。显然,假设您的计算机有足够的 RAM,您需要将其设置为几千兆字节才能使其正常工作(例如 -Xmx8g
)。
实例化数组时出现 OutOfMemoryError
的第二个原因是您超出了最大数组大小。这肯定发生在这里。最大数组大小未由 Java 语言规范定义,并且因 JVM 的不同而不同。在大多数 modern 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所做的就是工作mod232。另一种看待它的方式是,JVM 将加上或减去 232 的倍数,以使答案在正确的范围内。
这意味着Integer.MAX_VALUE + 16
的值实际上在数值上等于Integer.MAX_VALUE + 16 -
232,这是一个很大的负数。正如我前面提到的,StringBuffer
构造函数尝试实例化一个数组,其大小是您传递的值。这种实例化负大小数组的尝试为您提供了 NegativeArraySizeException
.