Java 堆 space 大文件错误 string.split
Java heap space error at large files with string.split
我在另一台机器上出现堆 space 错误,但它在我的机器上运行
我不能碰碰另一台机器的特性。
我如何在不使用的情况下解决这个问题
Scanner.java ?
string.split 的论点是否正确,用于在 space 秒后将字符串拆分成多个部分的“”?
[文件:]
U 1 234.003 30 40 50 true
T 2 234.003 10 60 40 false
Z 3 17234.003 30 40 50 true
M 4 0.500 30 40 50 true
/* 1000000+ lines */
java.lang.OutOfMemoryError: Java heap space
at java.base/java.util.Arrays.copyOfRange(Arrays.java:3821)
at java.base/java.lang.StringLatin1.newString(StringLatin1.java:764)
at java.base/java.lang.String.substring(String.java:1908)
at java.base/java.lang.String.split(String.java:2326)
at java.base/java.lang.String.split(String.java:2401)
at project.FileR(Fimporter.java:99)
public static DataBase File(String filename) throws IOException {
BufferedReader fs = new BufferedReader(new FileReader(filename),64 * 1024);
String line;
String[] wrds;
String A; int hash; double B; int C; int D; boolean E; DataBase DB = new DataBase();
while (true) {
line = fs.readLine();
if (line == null) {break;}
wrds = line.split(" "); /* this is line 99 in the error-message */
hash = Integer.parseInt(wrds[1]);
B = Double.parseDouble(wrds[2]);
C = Integer.parseInt(wrds[3]);
D = Integer.parseInt(wrds[4]);
E = Boolean.parseBoolean(wrds[5]);
// hash is hashcode for all values B C D E in DataBase DB
DB.listB.put(hash,B);
DB.listC.put(hash,C);
DB.listD.put(hash,D);
DB.listE.put(hash,E);
}
如果我没记错的话,您可以在启动 jar 文件时分配更多的堆大小,例如:
java -Xmx256M -jar MyApp.jar
这意味着,您可以更改这些设置。
但话又说回来,仅仅增加堆大小并不能解决这个问题,如果文件变大,发生 oom 的机会也会增加。
您可以考虑在处理之前拆分大文件,例如只处理前 X 行,然后强制 GC 运行(通过清零)然后处理下一行。
How can I solve this problem without using Scanner.java ?
Scanner
不是问题。
如果您使用此代码出现 OOME,最可能的根本原因如下:
DB.listB.put(hash,B);
DB.listC.put(hash,C);
DB.listD.put(hash,D);
DB.listE.put(hash,E);
您似乎正在将所有数据加载到 4 个地图中。 (您没有向我们展示相关代码......但我在这里做出有根据的猜测。)
我的第二个猜测是你的输入文件非常大,并且在上面的数据结构中保存它们所需的内存量对于“其他”来说太大了机器的堆。
OOME 发生在 String.split
调用中这一事实并不表示 split
本身存在问题。这就是俗话说的“压死骆驼的最后一根稻草”。问题的根本原因在于拆分后对数据所做的处理。
可能的解决方案/解决方法:
增加“其他”机器上的堆大小。如果您没有设置 -Xmx
或 -Xms
选项,JVM 将使用默认的最大堆大小...通常是物理内存的 1/4。
阅读 java
命令的 command documentation 以了解 -Xmx
和 -Xms
的作用以及如何设置它们。
使用内存效率更高的数据结构:
创建一个class来表示由B、C、D、E值组成的元组。然后用这些元组的映射替换这4个映射。
使用内存效率更高的 Map
类型。
考虑使用经过排序的元组数组(包括散列)并使用二进制搜索来查找它们。
重新设计你的算法,这样它们就不会同时需要内存中的所有数据;例如将输入拆分为更小的文件并分别处理它们。 (这可能是不可能的....)
我在另一台机器上出现堆 space 错误,但它在我的机器上运行 我不能碰碰另一台机器的特性。 我如何在不使用的情况下解决这个问题 Scanner.java ?
string.split 的论点是否正确,用于在 space 秒后将字符串拆分成多个部分的“”?
[文件:]
U 1 234.003 30 40 50 true
T 2 234.003 10 60 40 false
Z 3 17234.003 30 40 50 true
M 4 0.500 30 40 50 true
/* 1000000+ lines */
java.lang.OutOfMemoryError: Java heap space
at java.base/java.util.Arrays.copyOfRange(Arrays.java:3821)
at java.base/java.lang.StringLatin1.newString(StringLatin1.java:764)
at java.base/java.lang.String.substring(String.java:1908)
at java.base/java.lang.String.split(String.java:2326)
at java.base/java.lang.String.split(String.java:2401)
at project.FileR(Fimporter.java:99)
public static DataBase File(String filename) throws IOException {
BufferedReader fs = new BufferedReader(new FileReader(filename),64 * 1024);
String line;
String[] wrds;
String A; int hash; double B; int C; int D; boolean E; DataBase DB = new DataBase();
while (true) {
line = fs.readLine();
if (line == null) {break;}
wrds = line.split(" "); /* this is line 99 in the error-message */
hash = Integer.parseInt(wrds[1]);
B = Double.parseDouble(wrds[2]);
C = Integer.parseInt(wrds[3]);
D = Integer.parseInt(wrds[4]);
E = Boolean.parseBoolean(wrds[5]);
// hash is hashcode for all values B C D E in DataBase DB
DB.listB.put(hash,B);
DB.listC.put(hash,C);
DB.listD.put(hash,D);
DB.listE.put(hash,E);
}
如果我没记错的话,您可以在启动 jar 文件时分配更多的堆大小,例如:
java -Xmx256M -jar MyApp.jar
这意味着,您可以更改这些设置。
但话又说回来,仅仅增加堆大小并不能解决这个问题,如果文件变大,发生 oom 的机会也会增加。
您可以考虑在处理之前拆分大文件,例如只处理前 X 行,然后强制 GC 运行(通过清零)然后处理下一行。
How can I solve this problem without using Scanner.java ?
Scanner
不是问题。
如果您使用此代码出现 OOME,最可能的根本原因如下:
DB.listB.put(hash,B);
DB.listC.put(hash,C);
DB.listD.put(hash,D);
DB.listE.put(hash,E);
您似乎正在将所有数据加载到 4 个地图中。 (您没有向我们展示相关代码......但我在这里做出有根据的猜测。)
我的第二个猜测是你的输入文件非常大,并且在上面的数据结构中保存它们所需的内存量对于“其他”来说太大了机器的堆。
OOME 发生在 String.split
调用中这一事实并不表示 split
本身存在问题。这就是俗话说的“压死骆驼的最后一根稻草”。问题的根本原因在于拆分后对数据所做的处理。
可能的解决方案/解决方法:
增加“其他”机器上的堆大小。如果您没有设置
-Xmx
或-Xms
选项,JVM 将使用默认的最大堆大小...通常是物理内存的 1/4。阅读
java
命令的 command documentation 以了解-Xmx
和-Xms
的作用以及如何设置它们。使用内存效率更高的数据结构:
创建一个class来表示由B、C、D、E值组成的元组。然后用这些元组的映射替换这4个映射。
使用内存效率更高的
Map
类型。考虑使用经过排序的元组数组(包括散列)并使用二进制搜索来查找它们。
重新设计你的算法,这样它们就不会同时需要内存中的所有数据;例如将输入拆分为更小的文件并分别处理它们。 (这可能是不可能的....)