Spring Boot从1.3.2升级至1.5.22后触发OOM错误求助
看起来你在升级Spring Boot版本后遇到了棘手的内存溢出问题——从栈跟踪信息来看,问题出在ContentCachingRequestWrapper创建ByteArrayOutputStream时,请求的数组大小超出了JVM限制。这大概率是因为Spring Boot 1.5版本中的请求日志/跟踪过滤器默认会无限制缓存整个请求体,当遇到大请求时直接触发了内存溢出。
下面是针对性的解决方案,按优先级排序:
方案1:限制请求缓存的最大大小
这是最直接的根治方法,通过配置限制过滤器缓存的请求体大小,避免无限制占用内存:
针对WebRequestTraceFilter
在application.properties或application.yml中添加配置,设置允许缓存的最大内容长度(比如设为1MB):
# 开启请求跟踪过滤器的同时,限制最大缓存内容长度 endpoints.trace.filter.enabled=true endpoints.trace.max-content-length=1048576
针对自定义的AbstractRequestLoggingFilter实现
如果你的代码里有继承AbstractRequestLoggingFilter的请求日志过滤器,直接在Bean配置中设置最大缓存大小:
@Bean public CommonsRequestLoggingFilter requestLoggingFilter() { CommonsRequestLoggingFilter loggingFilter = new CommonsRequestLoggingFilter(); loggingFilter.setIncludeClientInfo(true); loggingFilter.setIncludeQueryString(true); loggingFilter.setIncludePayload(true); // 设置最大缓存的请求体大小为1MB loggingFilter.setMaxPayloadLength(1048576); return loggingFilter; }
方案2:禁用不必要的请求缓存过滤器
如果你的应用不需要请求跟踪或请求日志功能,可以直接禁用对应的过滤器,从根源上避免缓存行为:
禁用WebRequestTraceFilter
在配置文件中添加:
endpoints.trace.enabled=false
禁用自定义请求日志过滤器
如果是你自己配置的AbstractRequestLoggingFilter子类,直接注释掉对应的@Bean配置,或者通过配置开关控制是否初始化该过滤器。
方案3:自定义缓存逻辑(进阶)
如果必须缓存请求内容但需要更灵活的控制,可以自定义ContentCachingRequestWrapper的子类,在缓存时主动限制内容大小,超过阈值就停止缓存:
public class LimitedContentCachingRequestWrapper extends ContentCachingRequestWrapper { // 定义最大缓存大小为1MB private static final int MAX_CACHE_SIZE = 1048576; public LimitedContentCachingRequestWrapper(HttpServletRequest request) { super(request); } @Override protected void writeToCache(byte[] b, int off, int len) { // 检查当前缓存长度加上新内容是否超过阈值,超过则停止缓存 if (getCachedContentLength() + len > MAX_CACHE_SIZE) { return; } super.writeToCache(b, off, len); } }
之后在对应的过滤器中,用这个自定义包装类替代默认的ContentCachingRequestWrapper即可。
额外建议
- 检查栈跟踪里的其他自定义过滤器(比如
ariba.HttpWrapperFilter),确保它们也没有无限制缓存请求内容。 - 单纯调大JVM堆内存(比如
-Xmx参数)只能临时缓解,无法从根本上解决无限制缓存大请求的问题,优先考虑前面的方案。
内容的提问来源于stack exchange,提问作者Pradeep Balasubramaniam

