有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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) 个答案

  1. # 1 楼答案

    自Spring 5.3以来,exchange()方法在web客户端上已被弃用,因为它可能会导致内存和连接泄漏。通过使用exchange(),您承担了为每个场景使用响应内容的责任

    从上面的代码示例来看,在成功和错误的情况下,您并没有使用主体

    您还可以设置以下属性,以便从netty获得有关泄漏来源的其他信息

    -Dio.netty.leakDetection.level=paranoid

    Exchange Javadoc

    Netty Leak Detection Docs