我得到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 task来运行它。
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:DirectBufferMemory”
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;
}
我没有springwebflux5.3在组织repo中。所以我不能用这个。
这是默认的内存配置
-Xmx1387828K -Xss1M -XX:ReservedCodeCacheSize=240M -XX:MaxDirectMemorySize=10M -XX:MaxMetaspaceSize=197323K
1条答案
按热度按时间pxy2qtax1#
从5.3年Spring开始
exchange()
方法在web客户端上已被弃用,因为它会打开内存和连接泄漏的可能性。通过使用exchange()
您负责为每个场景使用响应内容。从上面的代码示例可以看出,在成功和错误的情况下,您不会使用主体。
您还可以设置以下属性,以便从netty获得有关泄漏来源的其他信息。
-dio.netty.leakdetection.level=偏执狂
交换javadoc
netty泄漏检测文件