java - 为什么“while(Scanner.hasNext())”会在 java 中导致 OutOfMemoryError?
问题描述
import java.util.*;
import java.io.*;
public class Main {
public static void problem1 () {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
int n = scanner.nextInt();
int[][] nums = new int[n][2];
for (int i = 0; i < n; i++) {
nums[i][0] = scanner.nextInt();
nums[i][1] = scanner.nextInt();
}
Arrays.sort(nums, (a, b) -> {
return a[0] - b[0];
});
int[] dp = new int[n];
Arrays.fill(dp, 1);
int res = 1;
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
if (nums[i][1] >= nums[j][1]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
if (dp[i] > res)
res = dp[i];
}
System.out.println(res);
}
}
public static void main(String[] args) throws IOException {
problem1();
}
}
在对上述代码进行编码时,我发现while(scanner.hasNext())
会导致"OutOfMemoryError: Java heap space"
输入数据超过1000000;并且这个bug可以通过去掉while循环来解决;但在我有限的 JVM 经验中,我不知道为什么;有任何想法吗?
解决方案
我们确实需要查看输入以确定失败的原因。但是,如果您在 OOME 中获得了 OOME hasNext()
,那么正在发生的事情是您的应用程序的输入包含一个非常长的令牌。
该hasNext()
调用将从当前位置对输入流进行预读,直到遇到指示下一个标记结束的字符(或 EOF)。预先读取的字符需要在内存中缓冲。OOME 意味着您在缓冲字符时已设法填满堆。
一个可能的“快速而肮脏”的解决方法是使堆大小足够大以缓冲整个输入。 但我认为这不会奏效。
为什么?
假设您设法缓冲了一个大得惊人的令牌,以便它hasNext()
可以返回true
。您要做的下一件事是调用nextInt()
以读取n
. 但这很可能会失败,因为令牌(由 找到hasNext()
)不是数字,或者数字太大而无法作为int
. 所以nextInt()
会抛出异常。
解决这个问题的真正方法是弄清楚这个可怕的令牌到底是什么。这需要查看您的应用程序正在读取的输入。
并且这个bug可以通过去掉while循环来解决;
嗯。
我认为这意味着如果您删除外循环,OOME 就会消失。你实际上并没有解决问题。现在您的代码将只处理一个数据集。
推荐阅读
- python - Python urllib 请求与在浏览器中单击不同
- java - 为什么静态嵌套类看起来有实例字段?
- java - 使用正则表达式在 XML 标记中搜索和替换“@”值
- python - Python 等价于 IDL median() 和 rot()
- azure-active-directory - Azure AD 异常 - AADSTS50105 - “登录的用户未分配给应用程序的角色”。是否可以修改此消息?
- php - 从 MySQL SELECT 的对象中创建对象
- javascript - 如何根据类知道元素?
- android - ionic中的Android构建错误-包括Cordova插件文件
- c# - 重试失败的任务列表
- android - kotlinx.serialization 使用自定义序列化程序将 Int 转换为 Boolean