Java 在while循环内的for循环中追加字符串时出现OOM错误

Java 在while循环内的for循环中追加字符串时出现OOM错误,java,out-of-memory,stringbuilder,nested-loops,Java,Out Of Memory,Stringbuilder,Nested Loops,对于模拟,我希望能够有一个高达10000个时间步的while循环。 在每个时间点,我都希望存储项目的实例变量。在我的真实代码中,项目是在每个时间点经历转换的对象,但这是导致OOM错误的原因 因为代码中的字符串正在消耗我的堆内存,而不是因为我的项的转换 在每个时间点,我都希望将项目的实例变量写入StringBuilder,然后将其传输到for循环外部但在while(time)循环内的字符串数组 我使用for循环迭代所有项,并将所有实例变量附加到一行中,以“%”分隔,以便能够分隔数据以供以后使用 如

对于模拟,我希望能够有一个高达10000个时间步的while循环。 在每个时间点,我都希望存储项目的实例变量。在我的真实代码中,项目是在每个时间点经历转换的对象,但这是导致OOM错误的原因 因为代码中的字符串正在消耗我的堆内存,而不是因为我的项的转换

在每个时间点,我都希望将项目的实例变量写入StringBuilder,然后将其传输到for循环外部但在while(time)循环内的字符串数组

我使用for循环迭代所有项,并将所有实例变量附加到一行中,以“%”分隔,以便能够分隔数据以供以后使用

如果我使用多达5000个时间步和1000个项目,我的代码工作正常。但当我将时间步长增加到6000时,就会出现内存不足错误

这是我的密码

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class Test2 {
    public static void main(String[] args) throws IOException {

        int time = 0;
        int endTime = 6000;
        int items = 1000;
        File FILE = new File("test.txt");

        String[] arrayString = new String[endTime];

        while (time < endTime) {
            StringBuilder sb = new StringBuilder(50 * items);

            for (int i = 0; i < items; i++) {

                sb.append("Data from my items I want to store in a textfile.")
                  .append("%");         // '%' functions as a split-symbol between
                                        // two items that I later use as
                                        // delimiter for loading the text file
            }

            arrayString[(int) time] = sb.toString();
            sb.delete(0, sb.length());
            sb.setLength(50 * items);

            time++;
        }
        PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(
                FILE, true)));
        for (int j = 0; j < endTime; j++) {
            pw.println(arrayString[j]);
        }
        pw.close();
        System.out.println("Done");
    }
}


我是否达到了字符串数组中可以存储多少字符串的限制?还是有什么方法可以改进我的代码(结构)以避免出现OOM错误?

这里可能有很多因素<代码>阵列字符串将需要300MB内存。如果这大于最大内存大小,那就是您的问题所在。如果您的最小大小较小,那么垃圾回收器在试图获取它真正需要的内存时会变慢

接下来,您将重复创建一个大约需要50KB的StringBuilder实例。这个空间可能会被有效回收,也可能不会被有效回收,但GC完全回收更大的空间通常需要时间。因此,您可以只使用最大内存的50%或更少,而GC却永远无法真正释放任何空间。(并不是说50KB比300MB大,但我想我应该提一下。)

最后一个问题是,如果GC开始花费太长时间,它就会放弃并抛出OutOfMemoryError。即使理论上有足够的内存可用,也可能发生这种情况

最简单的修复方法是为它提供更多的最小和最大内存。不要认为,因为你没有使用最大内存,你就不会受到OOM的威胁

同样值得注意的是,快速分配和释放内存会伤害你。交叉使用一些需求较少的代码(更少的新代码和更小的大小)可以给GC更多的时间来组织内存。有了更长的截止日期,GC不会落后太多,尽管所需的工作是一样的,因此它不会放弃和抛出OOM


编写GCs的人总是在调整它们,并试图进行更好的权衡,因此准确地说出GCs正在做什么,或者他们明天将要做什么有点棘手。在这里,我只是想给你一些想法。

在提问之前,你应该先完成作业。每个元素有49个字符长。将其附加到StringBuilder中1000次,得到一个长度为49000个字符的字符串。然后将其添加到6000个元素长的数组中,总共占用294000000字节的空间。您可以在启动JVM时增加堆的大小,以查看这对错误点的影响。非常感谢,我增加了堆内存,并使字符串数组中的数据存储尽可能有限。现在我可以运行30000次代码了。
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOfRange(Unknown Source)
    at java.lang.String.<init>(Unknown Source)
    at java.lang.StringBuilder.toString(Unknown Source)
    at package2.Test2.main(Test2.java:30)
arrayString[(int) time] = sb.toString();