如何解决Java使用String.repeat时的内存溢出及字符串最大长度问题
Java String.repeat 内存溢出问题解答
字符串最大长度说明
你查询到的「Java字符串最大长度为2147483647」是理论上限,并非所有场景下都能达到:
- String的
length()方法返回值为int类型,因此字符数的理论最大值确实是int的上限2147483647 - 实际运行中最大长度受JVM堆内存大小限制:字符串底层用char数组存储,申请的连续堆内存不足时,就算字符数没到理论上限,也会抛出
java.lang.OutOfMemoryError - 额外限制:部分旧版本JVM的数组对象头会占用额外存储,实际可存储的最大字符数会比2147483647小几个字节
代码触发OOM的原因
你只考虑了字符串的理论长度上限,没有把JVM实际可用堆内存纳入计算,所以当理论计算的最大次数对应的字符串大小超过当前JVM可分配的堆内存时,就会触发内存溢出。
另外你的代码有一个小的逻辑瑕疵:拼接后的d = 原字符串 + 空格,调用repeat(a)之后末尾会多出一个不必要的空格。
解决方案
方案1:修正最大安全次数计算逻辑
你需要同时取理论上限和内存允许上限的较小值作为最大可输入次数:
// 计算理论最大次数 int unitLen = b.length() + 1; int maxTheoretical = Integer.MAX_VALUE / unitLen; // 计算内存允许的最大次数,按可用堆内存的70%计算安全阈值,单个char占2字节 long maxAvailableMem = (long) (Runtime.getRuntime().maxMemory() * 0.7); long maxByMem = maxAvailableMem / (unitLen * 2L); // 最终允许的最大次数 int maxAllowed = (int) Math.min(maxTheoretical, maxByMem);
方案2(更推荐):放弃拼接大字符串
如果只是需要将重复内容输出到控制台,完全不需要拼接成一个完整的大字符串,可以直接循环输出,不管重复多少次都不会触发内存溢出:
// 替换d.repeat(a)的逻辑 for (int i = 0; i < a; i++) { System.out.print(d); } // 最后输出换行 System.out.println();
内容的提问来源于stack exchange,提问作者Darshit Sharma 8th C
相关产品推荐
相关产品推荐

