String 的性能优化,真能省不少内存
String 是我们每天都在用的基础类型,但很多时候,真正决定性能和内存占用的,反而就是它。理解得越透,越能在一些看似普通的场景里省下不少资源。
这篇文章从 String 的结构、不可变性,到字符串拼接、intern() 以及分割技巧,梳理几个在实际开发里很常见、也很容易被忽略的优化点。
String 的结构演进
要理解 String 为什么能做这些优化,先看它在不同版本里的内部实现。
Java 6 及之前
在 Java 6 及更早版本里,String 底层保存的是 char[],并通过 offset 和 count 来定位数组中的一段内容。
这种设计的好处很直接:substring() 可以共享原始数组,不用额外拷贝,速度快,也省内存。
但问题也正出在这里。substring() 虽然返回了一个新的字符串对象,可它底层指向的还是同一个 char[]。如果原始大字符串还被某个小片段引用着,那整块数组都回收不了,时间一长,就可能把内存拖出问题。
String(int offset, int count, char value[]) {
this.value = value;
this.offset = offset;
this.count = count;
}
public String substring(int beginIndex, int endIndex) {
// check boundary
return new String(offset + beginIndex, endIndex - beginIndex, value);
}
JDK 7、8
到了 JDK 7 和 8,offset、count 被移除了,substring() 也不再共享原始数组,而是改成复制一份新的 char[]。
这样做的代价是多了一次拷贝,但收益也很明显:彻底避免了因为共享数组导致的内存泄漏问题。
public String(char value[], int offset, int count) {
this.value = Arrays.copyOfRange(value, offset, offset + count);
}
public String substring(int beginIndex, endIndex) {
endIndex - beginIndex;
(value, beginIndex, subLen);
}


