如何向Tomcat上传100MB以上文件?修改配置后遇OutOfMemoryError怎么办
java.lang.OutOfMemoryError问题 兄弟,太懂这种改了参数反而炸内存的憋屈了——你调大maxPostSize允许更大的请求,但Tomcat默认会把整个请求体(包括你的大文件)直接加载到JVM内存里,文件一超大,内存直接就顶不住了。下面给你几个靠谱的解决方向:
调整Tomcat的请求体存储策略
Tomcat有个容易被忽略的参数maxSavePostSize,在server.xml的Connector节点里配置,它决定了当请求体超过多大时,Tomcat会把内容写到临时磁盘文件,而不是死死占着内存。建议设置成maxSavePostSize="-1"(-1表示不限制,所有超过内存缓存阈值的请求体都转存磁盘),搭配你已经修改的参数,完整配置大概是这样:<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" maxPostSize="104857600" <!-- 这里设成你需要的最大文件大小,比如100MB --> maxHttpHeaderSize="81920" maxSavePostSize="-1" />另外要注意Tomcat的临时目录(默认是
CATALINA_BASE/temp)要有足够的磁盘空间,不然存临时文件会出别的岔子。优化JVM内存分配
如果你的应用本身堆内存分配太小,就算用了磁盘缓存,处理大文件时也可能触发溢出。去catalina.sh(Linux)或catalina.bat(Windows)里调整JVM参数:# Linux示例:初始堆2G,最大堆4G,根据服务器配置调整 export JAVA_OPTS="-Xms2g -Xmx4g" # Windows示例 set JAVA_OPTS="-Xms2g -Xmx4g"别贪多,堆内存最好不要超过服务器物理内存的70%,避免和系统进程抢资源。
改用分块上传(最彻底的方案)
把大文件切成小 chunks(比如每个10MB),前端分多次上传,后端接收后再合并。这样每次请求的内存占用都极小,完全不会触发内存溢出,还能支持断点续传,用户体验也更好。
实现的时候,后端可以用MultipartFile接收每个分块,记录好分块序号和文件唯一标识,所有分块传完后再拼接成完整文件。检查你的代码处理逻辑
有时候问题不在Tomcat,而是你自己的代码把整个文件读到内存里了——比如用FileUtils.readFileToByteArray或者把MultipartFile转成byte[]存起来。这种情况要改成流式处理,直接把输入流写到磁盘,别先读进内存:// 糟糕的写法:把整个文件加载到内存 byte[] fileBytes = multipartFile.getBytes(); Files.write(Paths.get("target/file"), fileBytes); // 推荐的写法:流式写入,内存占用极低 try (InputStream in = multipartFile.getInputStream(); OutputStream out = new FileOutputStream("target/file")) { byte[] buffer = new byte[8192]; int bytesRead; while ((bytesRead = in.read(buffer)) != -1) { out.write(buffer, 0, bytesRead); } } catch (IOException e) { // 处理异常逻辑 }
按优先级来,先调Tomcat的存储策略,再检查代码,最后考虑分块上传,基本能解决你的问题。
内容的提问来源于stack exchange,提问作者Desmond




