String类subString方法为何会引发内存溢出?
String.substring() 引发内存溢出的原理
首先明确:这个问题只存在于JDK 6及更早版本,JDK 7及之后已经修复了该缺陷。
JDK 6 中的问题根源
- String类的内部结构
JDK 6里的String对象包含三个核心字段:
char[] value:存储实际字符的底层数组int offset:字符数组中当前String的起始偏移量int count:当前String的字符长度
substring()的实现逻辑
调用substring(int beginIndex, int endIndex)时,JDK 6会直接创建一个新的String对象,但不会复制原字符串的char[],而是复用原数组,仅修改新String的offset和count字段来指向原数组的对应片段。内存溢出的触发场景
假设你有一个超大的String对象(比如几GB的文本),当你用substring()截取其中很小的一部分(比如几个字符)后,原超大String对象即使被回收,新生成的小String对象仍会持有原超大char[]的引用。只要这个小String还存在于内存中,原超大char[]就无法被GC回收。如果大量生成这类小String,内存会被这些“无用”的超大char[]持续占用,最终引发OutOfMemoryError。
JDK 7+ 的修复方案
JDK 7及之后彻底修改了substring()的实现:调用该方法时,会直接复制需要的字符片段到新的char[]中,新String对象不再引用原数组。这样即使原大String被回收,对应的char[]也会被正常GC,不会再出现内存泄漏问题。
示例代码(JDK 6 场景)
// 创建一个100MB的超大字符串 String largeString = new String(new char[1024 * 1024 * 100]); // 截取仅10个字符的小字符串 String smallString = largeString.substring(0, 10); // 此时largeString可被回收,但smallString持有原100MB的char[]引用,该数组无法释放
内容的提问来源于stack exchange,提问作者Shubham
相关产品推荐
相关产品推荐

