Step 5 Preview 实测:MoE 架构与 1M 上下文在跨模块重构和视觉编程中的真实表现
2026/11/3 17:44:54
“不要在 Bean(尤其是单例 Bean)里积累大量数据(比如往 List 无限 add)”
其实是在提醒一个非常常见但容易被忽视的内存泄漏(Memory Leak)问题。我们来用通俗的方式解释它。
假设你写了一个 Spring 单例 Service,用来记录用户操作日志:
@Service public class AuditService { // ⚠️ 危险!这个 list 会一直增长! private List<String> logs = new ArrayList<>(); public void log(String action) { logs.add(action); // 每次调用都往里加 } public List<String> getAllLogs() { return logs; } }你的应用部署上线,每天有成千上万用户访问,log()方法被频繁调用。
logs列表越来越大:100 条 → 1 万条 → 100 万条……AuditService是单例,Spring 容器一直持有它。logs作为它的成员变量,也永远不会被释放。这就是典型的“内存泄漏”—— 不是内存真的丢了,而是不该留的数据一直占着不走。
public void process() { List<String> temp = new ArrayList<>(); // 方法结束就释放 // ... }LinkedBlockingQueue+ 固定容量)private static final int MAX_LOGS = 1000; private final Queue<String> logs = new LinkedBlockingQueue<>(MAX_LOGS); public void log(String action) { if (!logs.offer(action)) { // 队列满了,丢弃最旧的 or 报警 } }LoadingCache<String, Object> cache = Caffeine.newBuilder() .maximumSize(10_000) .expireAfterWrite(Duration.ofMinutes(10)) .build(key -> loadValue(key));如果你在方法里new ArrayList(),方法一结束,局部变量消失,对象就可能被 GC 回收。
但单例 Bean 的成员变量 = 全局变量!
只要 Bean 活着,这些数据就永远活在内存里。
Spring 单例 Bean 的生命周期 = 整个应用的生命周期。
所以,别把它们当成“临时仓库”,而要当成“长期住户”——东西放进去,就很难清掉了!
表格
| 场景 | 建议 |
|---|---|
| 记录日志 | 写文件 / 数据库 / 日志系统(Logback + ELK) |
| 缓存数据 | 用 Caffeine / Redis,别自己用 List/Map |
| 临时计算 | 用局部变量,别存到成员变量 |
| 必须存状态 | 加容量限制 + 清理机制 |
如果你正在开发高并发或长期运行的服务(比如 Web 后台、微服务),这一点特别重要!很多线上 OOM 事故,根源就是“无意识地在单例里攒数据”。