SpringWebClient:java。lang.OutOfMemoryError:直接缓冲内存
我正在学习java。lang.OutOfMemoryError:web客户端的直接缓冲区内存错误
批处理作业每天运行。它失败了两次,然后在第三次尝试中通过
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: -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);
}
编辑1:
我还发现CloudFoundary为堆设置了一个较低的mwmory 我正在使用CF任务来运行它
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
编辑2:
我已经更新了代码以在任何情况下使用响应。尽管如此,我还是得到了相同的“java.lang.OutOfMemoryError:直接缓冲内存”
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;
}
我在组织回购中没有SpringWebFlux 5.3。所以我不能用那个
这是默认的内存配置
-Xmx1387828K -Xss1M -XX:ReservedCodeCacheSize=240M -XX:MaxDirectMemorySize=10M -XX:MaxMetaspaceSize=197323K
# 1 楼答案
自Spring 5.3以来,
exchange()
方法在web客户端上已被弃用,因为它可能会导致内存和连接泄漏。通过使用exchange()
,您承担了为每个场景使用响应内容的责任从上面的代码示例来看,在成功和错误的情况下,您并没有使用主体
您还可以设置以下属性,以便从netty获得有关泄漏来源的其他信息
Exchange Javadoc
Netty Leak Detection Docs