You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决Multipart文件转发导致的java.lang.OutOfMemoryError问题?

低内存占用的Multipart文件接收与转发方案

问题根源

你当前用file.getResource()获取的是ByteArrayResource,会把整个文件内容加载到JVM堆内存里,大文件高并发场景下必然导致堆内存暴涨,且大对象容易进入老年代,GC无法及时回收,最终耗尽堆空间。

解决方案

1. 接收阶段:避免文件全量加载到内存

在Spring/Spring Boot中,强制所有上传文件直接写入磁盘,彻底避免内存占用:

  • Spring Boot项目中,在application.properties添加配置:
    spring.servlet.multipart.max-in-memory-size=0
    spring.servlet.multipart.location=/path/to/your/temp/dir # 指定临时文件存储目录,需配置磁盘清理策略
    
    配置后,所有上传的MultipartFile都会对应磁盘上的临时文件,而非内存中的字节数组。

2. 转发阶段:流式传输文件,不加载全量到内存

替换file.getResource()为FileSystemResource,直接引用磁盘临时文件,让下游请求时流式读取内容:

try {
    // 将MultipartFile转存到临时文件(若已在磁盘可跳过此步)
    File tempFile = File.createTempFile("upload_", ".tmp");
    file.transferTo(tempFile);
    tempFile.deleteOnExit(); // 进程退出时自动删除

    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.MULTIPART_FORM_DATA);
    MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
    // 用FileSystemResource替代ByteArrayResource,实现流式传输
    body.add("model", new FileSystemResource(tempFile));
    HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);

    // 发送请求到下游服务(示例用RestTemplate)
    restTemplate.postForObject("http://downstream-service/upload", requestEntity, String.class);

    // 请求完成后手动删除临时文件,避免磁盘占用
    tempFile.delete();
} catch (IOException e) {
    // 处理异常逻辑
}
  • 若使用CommonsMultipartFile,可直接获取已存在的磁盘文件路径,省去转存步骤:
    DiskFileItem fileItem = (DiskFileItem) ((CommonsMultipartFile) file).getFileItem();
    File tempFile = fileItem.getStoreLocation();
    body.add("model", new FileSystemResource(tempFile));
    

3. 配置RestTemplate支持流式传输

确保RestTemplate的FormHttpMessageConverter不会将文件内容加载到内存,关闭缓冲:

@Bean
public RestTemplate restTemplate() {
    RestTemplate restTemplate = new RestTemplate();
    for (HttpMessageConverter<?> converter : restTemplate.getMessageConverters()) {
        if (converter instanceof FormHttpMessageConverter) {
            FormHttpMessageConverter formConverter = (FormHttpMessageConverter) converter;
            formConverter.setBufferRequestBody(false); // 关闭请求体缓冲,保证流式传输
        }
    }
    return restTemplate;
}

4. 进阶:Spring WebFlux全流式处理

针对高并发大文件场景,推荐用Spring WebFlux实现全程非阻塞流式传输,中间服务几乎不占用内存:

// 接收请求的Controller
@PostMapping("/upload")
public Mono<String> uploadFile(@RequestPart("model") FilePart filePart) {
    // 用WebClient流式转发到下游服务
    return webClient.post()
            .uri("http://downstream-service/upload")
            .contentType(MediaType.MULTIPART_FORM_DATA)
            .body(BodyInserters.fromMultipartData("model", filePart))
            .retrieve()
            .bodyToMono(String.class);
}

// 配置WebClient
@Bean
public WebClient webClient() {
    return WebClient.create();
}

这种方式下,文件数据会从客户端直接流式传输到下游服务,中间节点仅负责转发数据流,内存占用极低。

额外注意事项

  • 临时文件目录需配置定期清理策略(比如Linux的tmpwatch或定时任务),避免磁盘被占满。
  • 监控磁盘使用情况,防止临时文件积压导致服务异常。

内容的提问来源于stack exchange,提问作者Anuj Ranaa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 04:02:43