trimToSize()通过新建≈length()大小的数组并复制有效字符来收缩StringBuilder底层数组容量,释放冗余内存;适用于拼接完成、长期只读、内存受限或大幅清空后等场景,需在toString()前调用才真正节省内存。

调用 trimToSize() 可以让 StringBuilder 把内部 char 数组的容量收缩到接近当前字符长度,从而释放未使用的堆内存。它不改变字符串内容,也不影响对象存活,是唯一能主动“瘦身”底层数组的方法。
trimToSize 是怎么工作的
StringBuilder 底层用一个 char[](JDK9+ 可能是 byte[])存内容,数组长度是 capacity,实际使用字符数是 length。默认构造容量为 16,即使只存了 3 个字符,也占着 16 个位置。trimToSize() 就是把这块数组重新分配成刚好容纳当前 length 的大小(或略多一点),丢弃冗余空间。
- 执行过程:新建一个长度 ≈ length() 的数组,把有效字符复制过去,替换原 value 引用
- 调用后 capacity() 通常明显下降,但不保证等于 length()(不同 JVM 实现可能保留 1~2 字节余量)
- 原数组失去引用,等待 GC 回收
什么情况下该调用 trimToSize
不是每次拼接完都要调,关键看是否长期持有且后续只读:
- 字符串拼接已全部完成,不再 append、insert 或 replace
- 对象会缓存较长时间(如放入静态 Map、作为配置模板复用)
- 明确关注内存占用,比如在内存受限环境、高频创建大量 StringBuilder 的批处理任务中
- 曾大幅扩容又清空(如 setLength(0) 或 delete 后 length 很小,但 capacity 仍很大)
怎么用才真正节省内存
光调用不够,得配合使用习惯:
立即学习“Java免费学习笔记(深入)”;
- 在最终调用 toString() 前调用 trimToSize() —— 这样 toString() 复制的数组更小,避免拷贝大片空白空间
- 避免先追加大量内容,再删掉大部分:此时 length 小但 capacity 没变,toString() 仍要复制整个大数组
- 如果之后还会复用这个 StringBuilder,就别 trimToSize,改用 setLength(0) 清空更高效
- 不要在循环内频繁调用:它本身有数组复制开销,仅当 length 比 capacity 小很多(比如不到 1/3)时才值得
和其他操作的区别
容易混淆的几个动作,作用完全不同:
- setLength(0):只重置 count,清空内容但保留原数组容量,适合循环复用
- sb = null 或离开作用域:靠 GC 回收整个对象,不收缩数组,也不释放中间冗余空间
- new StringBuilder(预估容量):从源头减少扩容次数,比事后 trimToSize 更省开销
- StringBuffer.trimToSize():行为一致,但 StringBuffer 因同步机制本就更重,优化收益相对低


















