Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does RestTemplate consume excessive amounts of memory?

Question

Why does Spring's RestTemplate use an excessive amount of heap (particularly the G1 Old Generation) when sending a file.

Context

We observed the RestTemplate to consume excessive amounts of memory when sending files via POST requests. We used Spring's WebClient as comparison and it behaves completely sane.

We created a demo project on github which contains the full code. The important parts are the following snippets:

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);
}

and

private void sendFileAsOctetStream(File file) {
    webClient.post()
            .uri("/file")
            .body(BodyInserters.fromResource(new FileSystemResource(file)))
            .exchange()
            .block();
}

We observed the memory usage with jconsole when sending a 550MB file with both the implementations (left is WebClient, right is RestTemplate. The WebClient cosumes a couple of MegaBytes while the RestTemplate requires 2.7 GigaByte:

enter image description here

  1. An initial manual GC to clean the old generation
  2. The request
  3. A manual GC (only for the RestTemplate)
like image 429
Trinova Avatar asked Jul 03 '20 11:07

Trinova


People also ask

Why RestTemplate is deprecated?

RestTemplate provides a synchronous way of consuming Rest services, which means it will block the thread until it receives a response. RestTemplate is deprecated since Spring 5 which means it's not really that future proof.

Which is better RestTemplate or WebClient?

Compared to RestTemplate , WebClient has a more functional feel and is fully reactive. Since Spring 5.0, RestTemplate is deprecated. It will probably stay for some more time but will not have major new features added going forward in future releases. So it's not advised to use RestTemplate in new code.

What is alternative for RestTemplate?

WebClient offers a modern alternative to the RestTemplate with efficient support for both sync and async, as well as streaming scenarios. The RestTemplate will be deprecated in a future version and will not have major new features added going forward. We are writing a new project using spring boot 2.0.

Is RestTemplate synchronous or asynchronous?

RestTemplate uses Java Servlet API and is therefore synchronous and blocking. Conversely, WebClient is asynchronous and will not block the executing thread while waiting for the response to come back. The notification will be produced only when the response is ready. RestTemplate will still be used.


1 Answers

This is due to the default RestTemplate which simply uses an unconfigured SimpleClientHttpRequestFactory for the creation of the requests.

The mentioned requst factory has a flag bufferRequestBody which by default is set to true, which leads to very high memory consumption when sending large requests.

From the javadoc of SimpleClientHttpRequestFactory#setBufferRequestBody():

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).

You can provide your own request factory, when creating the RestTemplate by using one of the other overloaded constructors, and setting mentioned flag to false on the request factory:

@Bean
public RestTemplate restTemplate() {
    SimpleClientHttpRequestFactory rf = new SimpleClientHttpRequestFactory();
    rf.setBufferRequestBody(false);
    return new RestTemplate(rf);
}
like image 199
Lino Avatar answered Sep 18 '22 08:09

Lino