减少临时对象创建是JVM性能调优最直接有效的手段,可降低Minor GC频率、避免对象过早晋升老年代、减少Full GC风险;常见高危场景包括循环内字符串拼接、频繁新建集合/包装类、方法内重复new DTO/VO、日志字符串拼接等。

减少临时对象创建是 JVM 性能调优中最直接、见效最快的手段之一。它不依赖复杂参数调整,而是从代码源头缓解年轻代压力,从而显著降低 Minor GC 频率,避免对象过早晋升到老年代,间接减少 Full GC 风险。
哪些场景容易产生高频临时对象
这些地方看似无害,实则 GC 压力主要来源:
-
循环内字符串拼接:如
str += "a"每次都生成新 String 对象(底层新建 StringBuilder 再 toString) -
循环中创建集合或包装类:比如
new ArrayList<>()或Integer.valueOf(i)在高频循环里反复调用 - 方法内反复 new 相同结构对象:如每次 HTTP 请求都 new 一个 DTO、VO 或工具类实例
-
日志参数构造:例如
log.info("user=" + user.getId() + ", name=" + user.getName()),即使日志级别未开启,字符串拼接仍执行
具体优化方式与写法对比
关键不是“不用对象”,而是“让对象不短命”:
- 字符串拼接统一用 StringBuilder:在确定长度或循环次数时,可预设容量,避免扩容复制
-
用基本类型代替包装类:如循环计数用
int而非Integer;集合需泛型时,优先考虑IntArrayList(如 Eclipse Collections)等原生类型集合 -
延迟拼接、条件拼接:日志改用占位符写法 ——
log.info("user={}, name={}", user.getId(), user.getName()),SLF4J 会在日志启用时才执行 toString - 提取复用逻辑到方法外:把循环内可复用的对象(如 SimpleDateFormat、JSONWriter)提到方法/类级别,并确保线程安全(如用 ThreadLocal 封装)
对象池适合哪些对象
对象池不是万能解药,只对满足以下条件的对象有价值:
立即学习“Java免费学习笔记(深入)”;
- 创建开销大:如数据库连接、HTTP 客户端、大缓存对象、加密上下文等
- 生命周期可控:能明确 borrow / return 边界,避免泄露
- 实例状态可重置:每次归还前能 clean 状态(如清空 buffer、重置标志位)
不建议池化的对象包括:简单 POJO、String、Integer、小 List 等 —— 池管理成本可能超过创建成本。
验证是否有效的小技巧
改完代码后,别只看业务逻辑是否正常,要确认 GC 压力确实下降:
- 用
jstat -gc <pid> 1000 5观察 Eden 使用率和 YGC 次数:Eden 波动更平缓、YGC 间隔拉长即为正向信号 - 开启 GC 日志(
-Xlog:gc*:file=gc.log:time,uptime,pid,tags,level),重点关注GC pause (G1 Evacuation Pause)的频率与 Eden 区回收量 - 对比优化前后堆直方图:
jmap -histo <pid>查看前 20 行中java.lang.String、java.util.ArrayList等临时对象实例数是否明显减少



















