问题描述
我正在获取java.lang.OutOfMemoryError:Web客户端上的直接缓冲区内存错误.
I am getting java.lang.OutOfMemoryError: Direct buffer memory error at the web client.
批处理作业每天运行.它失败两次,然后第三次尝试通过.
The batch job runs daily. It fails twice then passed in the third attempt.
at org.springframework.retry.support.RetryTemplate.rethrow(RetryTemplate.java:532) ~[spring-retry-1.2.5.RELEASE.jar:na]
Caused by: java.lang.OutOfMemoryError: Direct buffer memory
at reactor.netty.http.client.HttpClientDoOnError$OnErrorTcpClient.connect(HttpClientDoOnError.java:242) ~[reactor-netty-0.9.11.RELEASE.jar:0.9.11.RELEASE]
我在日志中找到的
JVM内存配置.它正在云铸造厂中运行.
JVM memory configuration which I found in the log. It is running in the cloud foundry.
JVM Memory Configuration: -Xmx342549K -Xss1M -XX:ReservedCodeCacheSize=240M -XX:MaxDirectMemorySize=10M -XX:MaxMetaspaceSize=194026K
失败的代码:
@Retryable(maxAttemptsExpression = "#{${remote.retry.maxAttempts}}", backoff = @Backoff(delayExpression = "#{${remote.retry.delay}}"))
public Optional<JobStatusResponseDTO> getStatus(String jobNumber, String accountNumber) {
return broadridgeClient.getStatus(accountNumber, jobNumber);
}
@CircuitBreaker(maxAttemptsExpression = "#{${remote.circuitBreaker.maxAttempts}}",
openTimeoutExpression = "#{${remote.circuitBreaker.openTimeout}}", resetTimeoutExpression = "#{${remote.circuitBreaker.resetTimeout}}")
public Optional<JobStatusResponseDTO> getStatus(String account, String jobNumber) {
JobStatusRequestDTO request = new JobStatusRequestDTO();
request.setAccount(account);
request.setJobNumber(jobNumber);
JobStatusResponseDTO jobStatus;
jobStatus = client.post()
.uri(PATH)
.body(BodyInserters.fromValue(request))
.exchange()
.elapsed()
.flatMap(response -> {
if (response.getT2().statusCode() == HttpStatus.NO_CONTENT) {
return Mono.empty();
} else if (isClientOrServerError(response.getT2())) {
return Mono.error(new RemoteClientException(String.format("Job status is not received: %s", response.getT2().statusCode())));
}
return response.getT2().bodyToMono(JobStatusResponseDTO.class);
})
.block();
return Optional.ofNullable(jobStatus);
}
我还发现,Cloud Foundry正在为堆设置较低的内存我正在使用CF任务来运行它.
I also found that cloud foundary is setting a low mwmory for heapI am using CF task to run it.
cf run-task ipbol-proxy-batch "JAVA_OPTS=\"-agentpath:\$PWD/.java-buildpack/oracle_jre/bin/jvmkill-1.16.0_RELEASE=printHeapHistogram=1 -Djava.io.tmpdir=\$TMPDIR -Djava.security.egd=file:///dev/urandom -XX:ActiveProcessorCount=\$(nproc) -Dspring.batch.job.names=${job_name} -Dbatch.run.historic=${run_historic_files} -Dorg.cloudfoundry.security.keymanager.enabled=false -Dorg.cloudfoundry.security.trustmanager.enabled=true -Djava.ext.dirs= -Djava.security.properties=\$PWD/.java-buildpack/java_security/java.security \$JAVA_OPTS\" && CALCULATED_MEMORY=\$(\$PWD/.java-buildpack/oracle_jre/bin/java-buildpack-memory-calculator-3.13.0_RELEASE -totMemory=\$MEMORY_LIMIT -loadedClasses=31842 -poolType=metaspace -stackThreads=250 -vmOptions=\"\$JAVA_OPTS\") && echo JVM Memory Configuration: \$CALCULATED_MEMORY && JAVA_OPTS=\"\$JAVA_OPTS \$CALCULATED_MEMORY\" && KEYSTORE_PARAMS=\$(\$PWD/.java-buildpack/oracle_jre/bin/java -jar \$PWD/.java-buildpack/oracle_jre/keystore-manager-0.1.1.jar) && JAVA_OPTS=\"\$JAVA_OPTS \$KEYSTORE_PARAMS\" && MALLOC_ARENA_MAX=2 VCAP_SERVICES=\$(for i in {1..10}; do \${PWD}/.java-buildpack/mv_decryptor/jpmc-mvdecryptor && exit 0; sleep 3; done; kill \$\$) SERVER_PORT=\$PORT eval exec \$PWD/.java-buildpack/oracle_jre/bin/java \$JAVA_OPTS -cp \$PWD/.::\$PWD/.java-buildpack/container_security_provider/container_security_provider-1.16.0_RELEASE.jar org.springframework.boot.loader.JarLauncher" ipbol-proxy-batch
我已更新代码以在每种情况下使用响应.不过,我仍然得到相同的"java.lang.OutOfMemoryError:直接缓冲内存"
I have updated the code to consume the response in every case. Still, I am getting the same "java.lang.OutOfMemoryError: Direct buffer memory"
public Optional<JobStatusResponseDTO> getStatus(String account, String jobNumber) {
JobStatusRequestDTO request = new JobStatusRequestDTO();
request.setAccount(account);
request.setJobNumber(jobNumber);
Optional<JobStatusResponseDTO> responseDTO = Optional.empty();
final Object block = client.post()
.uri(PATH)
.body(BodyInserters.fromValue(request))
.exchange()
.elapsed()
.flatMap(response -> {
if (response.getT2().statusCode() == HttpStatus.NO_CONTENT) {
return response.getT2().bodyToMono(Void.class).thenEmpty(Mono.empty());
} else if (isClientOrServerError(response.getT2())) {
return response.getT2().bodyToMono(Void.class).thenEmpty(Mono.error(new RemoteClientException(String.format("Job status is not received: %s", response.getT2().statusCode()))));
}
return response.getT2().bodyToMono(JobStatusResponseDTO.class);
})
.block();
if(block!= null && block instanceof JobStatusResponseDTO)
{
responseDTO = Optional.of((JobStatusResponseDTO)block);
}
return responseDTO;
}
我在组织存储库中没有Spring Webflux 5.3.所以不能使用它.
I don't have spring webflux 5.3 in organization repo. So can't use that.
这是默认内存配置
-Xmx1387828K -Xss1M -XX:ReservedCodeCacheSize=240M -XX:MaxDirectMemorySize=10M -XX:MaxMetaspaceSize=197323K
推荐答案
从Spring 5.3开始,Web客户端已弃用 exchange()
方法,因为它打开了可能的存储空间和连接泄漏.通过使用 exchange()
,您有责任消耗每种情况下的响应内容.
Since Spring 5.3 the exchange()
method has been deprecated on the web client due to the fact it opens up the possibility of memory and connection leaks. By using exchange()
you take on the responsibility to consume the response content for every single scenario.
从上面的代码示例中,您并没有在成功和错误情况下消耗主体.
From the code example above, you are not consuming the body in success and error cases.
您还可以设置以下属性,以从netty获取有关泄漏来源的其他信息.
You can also set the following property to get some additional information from netty on where the leaks are coming from.
这篇关于Webclient:java.lang.OutOfMemoryError:直接缓冲存储器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!