Spring Rest API Controller中的静态变量是否会引发内存泄漏?
关于Spring Controller静态变量是否导致内存泄漏的问题解答
参考代码
@RestController @RequestMapping("/v1") public class TransactionController { final static Logger logger = LogManager.getLogger(TransactionController.class); static Gson gson = new Gson(); @RequestMapping(value = "/create-transaction", method = RequestMethod.POST, produces = "application/json") public @ResponseBody String createTransaction(@RequestBody String json, HttpServletRequest request, HttpServletResponse response) { long startTime = System.currentTimeMillis(); try{ ... } catch (Exception ex) { logger.error(LogAdapter.logToLog4jException(startTime, request, "", json, gson.toJson("output here"), ex.toString()), ex); } } }
核心问题解答
静态变量是否会每次接口调用重新创建?
不会。Java中被static修饰的类成员属于类本身,仅在类第一次被类加载器加载时初始化1次,整个JVM运行生命周期内只会存在一份实例,所有接口请求、类实例都会共享该静态变量,不存在重复创建的问题。
是否推荐改为局部声明使用?
不推荐,原因如下:
- Logger的行业通用最佳实践就是声明为
private static final的类静态变量,改为局部声明反而需要每次请求都重新获取Logger实例,无意义且会产生额外性能开销。 - 无参构造的Gson实例本身是线程安全的,只要没有为Gson配置带状态的自定义TypeAdapter、序列化/反序列化器,全局复用单例Gson实例是性能最优的写法。如果改为局部声明每次调用都
new Gson(),会重复创建对象,增加不必要的GC压力。
内存泄漏排查方向
你当前的这两个静态变量写法是常规合理写法,不会导致内存泄漏,建议从以下方向排查泄漏原因:
- 检查是否有ThreadLocal变量使用后未调用
remove()方法清理:Spring Boot内置的Tomcat线程池会复用工作线程,若请求处理过程中往ThreadLocal存入内容后未清理,会导致线程绑定的对象一直无法被回收,产生泄漏。 - 检查其他静态集合类(如static修饰的List、Map)是否存在持续写入元素但未做清理、淘汰机制的情况,静态集合的生命周期和JVM一致,存入的对象会一直被持有无法释放。
- 检查是否有IO流、数据库连接、网络连接等外部资源使用完成后未正常关闭释放。
- 检查是否存在自定义的对象缓存、第三方组件缓存未设置容量上限和淘汰策略。
内容的提问来源于stack exchange,提问作者ghost123
相关产品推荐
相关产品推荐

