一个简单的场景:
private static final ExecutorService executor =
Executors.newCachedThreadPool();
public static void main(String... args) throws InterruptedException, ExecutionException {
Future<byte[]> f = null;
for (int i = 0; i < 10; i++) {
f = executor.submit(new Callable<byte[]>(){
@Override
public byte[] call() {
System.out.println("Starting task.");
try {
return new byte[1500 * 1024 * 1024]; // 1500 mb
}
finally {
System.out.println("Task complete.");
}
}
});
}
// System.out.println(f.get().length);
}
当我运行上面的代码时,它(据称)运行时没有错误。
(奇怪的是,当我在 NetBeans 中分析此代码时,会抛出 OutOfMemoryError 错误,但正常运行时则不会。)
所有 10 个“任务已完成。”消息立即显示,但时间范围对于实际分配字节数组来说太短了。
当我取消注释最后一行时,会抛出ExecutionException。
我知道代码示例有点荒谬...... 但为什么根本没有抛出异常,我怎样才能让 OutOfMemoryError 显示出来呢?我必须捕获它吗?这样操作安全吗?
最佳答案
您不应该捕获错误
- 它们的目的是让您的程序崩溃。您应该仅在以下情况下捕获 Exception
:你正在记录它/重新抛出它或者b。你正在处理它;您无法处理 OutOfMemoryError
,所以让它像预期那样使您的程序崩溃。
“任务完成”是在分配了 Future
对象时显示的,而不是在它们完成工作时显示的 - 您需要调用 f.get()
在每个 Future 上确保它完成了字节数组的分配。当您对其进行分析时,程序运行速度会变慢,这允许更多的Futures在Main方法终止之前分配它们的字节数组,这反过来又允许它们用完您的所有堆空间。 p>
将 f
更改为 futures 的 ArrayList(并将 f = executor.submit
更改为 f.add(executor.submit)
),然后迭代它并对其所有 future 调用 .get()
。这应该会在不使用探查器的情况下触发您的 OutOfMemoryError。
关于java - 为什么当 Future 抛出这个 OutOfMemoryError 时没有出现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16007345/