java.lang.OutOfMemoryError : Java 堆空间
Posted
技术标签:
【中文标题】java.lang.OutOfMemoryError : Java 堆空间【英文标题】:java.lang.OutOfMemoryError : Java heap space 【发布时间】:2011-10-24 05:04:26 【问题描述】:我在玩 Oracle 网站上的一些集合示例
public class Timing
public static void method()
List numbers = new ArrayList();
for (double i = 1; i <= Double.MAX_VALUE; i++)
numbers.add(new Double(i));
Collections.shuffle(numbers);
List winningcombination = numbers.subList(0, 10);
Collections.sort(winningcombination);
public static void main(String[] args)
long start = System.currentTimeMillis();
method();
long end = System.currentTimeMillis();
System.out.println("time elapsed : " + (end-start));
我试图查看 Double.MAX_VALUE 需要多长时间。我得到了这个:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Unknown Source)
at java.util.Arrays.copyOf(Unknown Source)
at java.util.ArrayList.ensureCapacity(Unknown Source)
at java.util.ArrayList.add(Unknown Source)
我有办法解决这个问题吗?
【问题讨论】:
实际异常发生在 ArrayList 选择增长(并将其旧内容复制到新的后备数组)时 【参考方案1】:有没有办法让您在Collection
中创建和存储Double.MAX_VALUE
对象?不,地球上没有那么多 RAM。 Double.MAX_VALUE
大约是 2 乘以 10 的 308 次方:即 2 后跟超过 300 个零。给 Best Buy 打个电话,看看他们会收取多少费用才能将其放入您的计算机。
【讨论】:
@OpenMind:解决办法是不要尝试不可能的事情。 没有解决办法。你不能存储那么多! 解决方案是为您的循环使用小得多的上限——例如,不超过一百万左右。 @OpenMind,你到底想做什么?生成10个保证不重复的随机数?如果是这样,请查看伪随机数生成器。另外,我不明白您为什么要生成 doubles 而不是 longs 或 alphanumerals 等的获胜组合。 写一个更好的算法,只存储已经选择的数字,如果你有相同的数字而你没有足够的数字,请再次随机。【参考方案2】:即使你有足够的内存,ArrayList
也最多可以有Integer.MAX_VALUE
元素。 Double.MAX_VALUE
远远超出上述限制。
在这种情况下,您在add
期间内存不足导致数组列表增长。
【讨论】:
超出“多少?” (我只想看一个大数字^^)【参考方案3】:您的代码无法工作的另一个原因:double
只能表示精确到大约 2^52 的整数 - 之后,i++
将不起作用,for
循环将永远不会终止。
您不应该使用浮点变量作为循环计数器。请改用int
或long
。
【讨论】:
虽然我认为如果代码尝试循环2^52
次可能已经存在问题... ;-)
好吧,这至少会给他带来一些意想不到的结果。那,而且因为他实际上测试了i <= Double.MAX_VALUE
,所以他无论如何都会溢出i
...
#winces# 我没有意识到不精确性得到了 that 糟糕,即使在上限范围内......哦,grr,它必须增加(正非零)十次方之后,不是吗...
@X-Zero:实际上是二的幂。并不是说不精确性变得更糟 - 它总是相同的,相对于所代表的数字的大小。一旦达到 2^52,(公正地)假设增加 1 并不重要。 OTOH,该格式可以区分 0.00000000000001 和 0.00000000000002 - 任何 尝试表示一个不可数的无限集合将需要一些权衡,而且它真的非常了不起,它可以仅在 64 位中完成并且工作得很好大多数时候。
...我真的在这里表明我缺乏计算机科学学位,不是...那个,并且太习惯于 AS/400 商店,大多数东西都在编码作为 BCD 【参考方案4】:
您应该只获得 10 个随机双精度数,而不是做您当前正在做的事情,将它们添加到 ArrayList 并对其进行排序。这基本上就是你的方法正在做的事情。
要获得随机双精度,请查看Random.nextDouble()
。
【讨论】:
【参考方案5】:您正在尝试分配 10^308 个值的顺序。这是很多价值观。
【讨论】:
放入真实的视角?10^308
看起来很小;p
@ PST 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.烨,看起来仍然小... 跨度>【参考方案6】:
增加堆的大小就可以了。只需使用此参数运行程序:
-Xmx512m
它会将您的堆大小增加到 512 MB。您可以指定任意数量:1g、2g 等等。
【讨论】:
【参考方案7】:for (double i = 1; i <= Integer.MAX_VALUE; i++)
numbers.add(new Double(i));
【讨论】:
但这将如何解决OutOfMemory
异常? (PC 仍然无法接近。)
这样更好,尽管您可能仍然没有那么多内存。大约有 20 亿个对象,每个对象至少 12 个字节,加上数组列表中的数组;所以 24GB 用于对象,另外 8B 用于数组。
@Ernest:嗯,消费级 PC 拥有 24GB 的 RAM 并非完全不可能;事实上,在 5 年后它可能会正常。
确实,这就是为什么我说“你可能还没有那么多”。我有一台服务器可以,但我的台式机都没有!【参考方案8】:
在你循环中:
for (double i = 1; i <= Double.MAX_VALUE; i++)
numbers.add(new Double(i));
如果有空间,ArrayList
只会将值添加到ArrayList
。如果不是,它将增加ArrayList
的大小,然后继续添加。
因此,当您创建此ArrayList
时,您基本上所做的是使用堆中分配的所有内存。如果您将ArrayList
变小,您应该能够将其保存在内存中。
【讨论】:
以上是关于java.lang.OutOfMemoryError : Java 堆空间的主要内容,如果未能解决你的问题,请参考以下文章