java - 为什么 RestTemplate 会消耗过多的内存?

标签 java spring spring-mvc resttemplate


为什么 Spring 的 RestTemplate 在发送文件时会使用过多的堆(尤其是 G1 Old Generation )。
语境
我们观察到 RestTemplate通过 POST 发送文件时消耗过多内存要求。我们使用了 Spring 的 WebClient作为比较,它的行为完全正常。
我们创建了一个 demo project on github其中包含完整代码。重要的部分是以下片段:

private void sendFileAsOctetStream(File file) {
    final RequestEntity<FileSystemResource> request = RequestEntity.post(URI.create("http://localhost:8080/file"))
            .contentType(MediaType.APPLICATION_OCTET_STREAM)
            .body(new FileSystemResource(file));
    restTemplate.exchange(request, void.class);
}

private void sendFileAsOctetStream(File file) {
    webClient.post()
            .uri("/file")
            .body(BodyInserters.fromResource(new FileSystemResource(file)))
            .exchange()
            .block();
}
我们通过 jconsole 观察内存使用情况当使用两种实现发送 550MB 文件时(左侧是 WebClient,右侧是 RestTemplateWebClient 消耗几个兆字节,而 RestTemplate 需要 2.7 GB:
enter image description here
  • 用于清理老年代的初始手动 GC
  • 请求
  • 手动 GC(仅适用于 RestTemplate)
  • 最佳答案

    这是由于默认 RestTemplate它只是使用一个未配置的 SimpleClientHttpRequestFactory用于创建请求。
    提到的请求工厂有一个标志 bufferRequestBody默认设置为 true ,这会导致发送大请求时内存消耗非常高。
    来自 SimpleClientHttpRequestFactory#setBufferRequestBody() 的 javadoc :

    Indicate whether this request factory should buffer the request body internally. Default is true. When sending large amounts of data via POST or PUT, it is recommended to change this property to false, so as not to run out of memory. This will result in a ClientHttpRequest that either streams directly to the underlying HttpURLConnection (if the Content-Length is known in advance), or that will use "Chunked transfer encoding" (if the Content-Length is not known in advance).


    您可以在创建 RestTemplate 时提供自己的请求工厂。通过使用其他重载构造函数之一,并将提到的标志设置为 false在请求工厂上:
    @Bean
    public RestTemplate restTemplate() {
        SimpleClientHttpRequestFactory rf = new SimpleClientHttpRequestFactory();
        rf.setBufferRequestBody(false);
        return new RestTemplate(rf);
    }
    

    关于java - 为什么 RestTemplate 会消耗过多的内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62714339/

    相关文章:

    java - 我应该为休息 Controller 和常规 Controller 创建单独的 Spring 安全设置吗?

    java - 警告 : No mapping found for HTTP request with URI [] in DispatcherServlet with name 'dispatcher'

    java - 从 Spring Controller 中删除重复项

    java - 如何使用 Spring MVC RequestMapping 有多个参数?

    spring-mvc - 在 STS 中测试新的 Spring MVC 项目 - 默认根上下文?

    jdbc - 由于设置类路径,java程序无法运行

    java - 如何使用 Jersey 将 POJO 序列化为查询参数

    java - 方向改变后 fragment 变成幽灵

    java - ThreadLocal 和 @Aspect 注解

    java - 为 Spring @Autowired 指定顺序