使用StringBuilder/StringWriter/String.format()追加大字符串时发生Java OutofMemoryException

使用StringBuilder/StringWriter/String.format()追加大字符串时发生Java OutofMemoryException,java,Java,我正在尝试解决一个编程问题,在这个问题中,我正在处理一个大字符串,我尝试使用String,StringBuilder,但在附加字符串时超出了MermoryException Java堆空间。 使用String.format()尝试StringWriter时,运行程序会花费很长时间(超过15分钟) 请建议当字符串长度为736778906400L时可以使用什么我已附上代码(git repo) 如果您只需要对重复字符串中的字符进行计数,请对其进行计数: static long repeate

我正在尝试解决一个编程问题,在这个问题中,我正在处理一个大字符串,我尝试使用String,StringBuilder,但在附加字符串时超出了MermoryException Java堆空间。 使用String.format()尝试StringWriter时,运行程序会花费很长时间(超过15分钟)

请建议当字符串长度为736778906400L时可以使用什么我已附上代码(git repo)


如果您只需要对重复字符串中的字符进行计数,请对其进行计数:

   static long repeatedString(String s, long n) {
        final char charToCheck='a';
        if (s.indexOf(charToCheck)>=1) {
            return s.chars()
                    .filter(value -> value == (int)charToCheck)
                    .count()*n;
        } else
            return 0;
    }

正如@Erwin Bolwidt和其他人指出的,StringBuffer对于大于int的最大值的值不起作用,并且还依赖于VM可用的内存。您的程序可能会在该限制之前的某个阶段或其他阶段命中OutOfMemory,因为StringBuffer.append的工作原理是重新分配一个更大的缓冲区,并在达到当前缓冲区大小时复制字符,因此您必须在内存中同时有两个巨大字符串的空间

通过使用构造函数“new StringBuffer(int someLength)”和要附加的字符数使infiniteString()预先调整大小,可以解决一些问题,这样可以避免在初始预调整大小后重新分配内部缓冲区

如果此时已经避免了OOM,那么infiniteString.toCharArray()行也会生成缓冲区的副本。如果使infiniteString()返回其StringBuffer,则可以在字符上循环时调用sb.charAt和sb.length,而不是char[]


每次调用String.valueOf(StringBuilder)都会复制缓冲区,这可能会加快OOM的速度。

为什么需要构建这么大的字符串?还有别的选择吗?文件?这是100%正常的,那么您希望得到什么呢?如果您每个字符使用一个字节(在较新的JDK中可能),那么该字符串的长度是686GB(技术上是Gibibyte)。只有当你至少有那么多的记忆时,你才能把它保存在记忆中。但是你正在对它进行操作,所以你需要更多的内存来保存副本。想出一种不同的方法,不需要同时将整个字符串保存在内存中。使用文件或拆分,然后尝试使用多个Threads@HiteshKumar实际上,使用多个线程并不能神奇地为您提供更多的内存它在第52行stringBuilder.append(strInput)追加时抛出OOM异常;这取决于你的问题。若您需要以任何方式计算字符串中的字符条目,那个么您不需要创建大字符串。使用乘法就足够了。如果您的问题是在任何情况下都要处理大字符串-这不是您的解决方案OPs字符串的长度为686 Gib字符。单个Java字符串或StringBuffer/StringBuilder不能容纳超过2Gib的字符,因为Java
int
不能容纳超过2^31-1的值