webclient:java.lang.outofmemoryerror:直接缓冲区内存

dohp0rv5  于 2021-07-06  发布在  Java
关注(0)|答案(1)|浏览(361)

我得到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
pxy2qtax

pxy2qtax1#

从5.3年Spring开始 exchange() 方法在web客户端上已被弃用,因为它会打开内存和连接泄漏的可能性。通过使用 exchange() 您负责为每个场景使用响应内容。
从上面的代码示例可以看出,在成功和错误的情况下,您不会使用主体。
您还可以设置以下属性,以便从netty获得有关泄漏来源的其他信息。
-dio.netty.leakdetection.level=偏执狂
交换javadoc
netty泄漏检测文件

相关问题