为什么Spring的RestTemplate G1 Old Generation
在发送文件时会使用过多的堆(尤其是)。
通过请求发送文件时,我们观察到RestTemplate消耗过多的内存POST
。我们使用Spring的WebClient作为比较,它的行为完全健全。
我们在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
,右为RestTemplate
。WebClient
总共消耗了2 兆字节,而RestTemplate
需要2.7 千兆字节:
RestTemplate
)这是由于默认设置RestTemplate
,该默认设置仅使用未配置SimpleClientHttpRequestFactory
的请求创建。
提到的requst工厂具有一个标志bufferRequestBody
,默认情况下将其设置为true
,这会在发送大请求时导致很高的内存消耗。
来自的javadoc SimpleClientHttpRequestFactory#setBufferRequestBody()
:
指示此请求工厂是否应在内部缓冲请求主体。默认为true。通过POST或PUT发送大量数据时,建议将此属性更改为false,以免耗尽内存。这将导致ClientHttpRequest要么直接流到基础HttpURLConnection(如果预先知道Content-Length),要么将使用“块传输编码”(如果预先不知道Content-Length)。
RestTemplate
使用其他重载的构造函数之一创建,并false
在请求工厂上将提到的标志设置为时,您可以提供自己的请求工厂:
@Bean
public RestTemplate restTemplate() {
SimpleClientHttpRequestFactory rf = new SimpleClientHttpRequestFactory();
rf.setBufferRequestBody(false);
return new RestTemplate(rf);
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句