Регистрация большой строки вызывает OutOfMemoryError - PullRequest
0 голосов
/ 05 сентября 2018

Веб-приложение My Spring Boot подключается ко многим внешним службам и требует записи всех запросов и ответов в службы и из них в файлы журналов.

Я использую Logback для механизма регистрации. А следующий код предназначен для распечатки ответного сообщения для файлов журнала.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

....

private static final Logger LOG = LoggerFactory.getLogger(RequestLoggingClientRequestInterceptor.class);

...

ClientHttpResponse response = execution.execute(request, body);
InputStream s = response.getBody();
String loggingResponseBody = new String(ByteStreams.toByteArray(s), Charset.forName("UTF-8"));
LOG.info("response status code: {}, response headers: {}, response body: {}",
            response.getStatusCode(),
            response.getHeaders(),
            loggingResponseBody);

Этот код имеет проблемы с производительностью. Он потребляет высокую загрузку ЦП, вызывает большие задержки, а в некоторых случаях, когда ответное сообщение очень большое, вызывает OutOfMemoryError при выполнении new String(ByteStreams.toByteArray(s), Charset.forName("UTF-8"));

Caused by: java.lang.OutOfMemoryError: Java heap space
    at java.lang.StringCoding.decode(StringCoding.java:215)
    at java.lang.String.<init>(String.java:463)
    at java.lang.String.<init>(String.java:515)
    at ...

Обратите внимание, что у меня нет особых требований для декодирования строки в 'UTF-8', я просто сделал это, потому что конструктор класса String предлагает.

Подскажите, пожалуйста, как улучшить код для решения проблемы с производительностью. Я попытался AsyncAppender, хотя это помогает с задержкой, я застрял с OutOfMemoryError.

1 Ответ

0 голосов
/ 05 сентября 2018

ClientHttpResponse должен быть закрыт (как указано), чего ByteStreams.toByteArray(s) нет (как указано).

try (InputStream s = response.getBody()) {
    LOG.info("response status code: {}, response headers: {}, response body:",
            response.getStatusCode(),
            response.getHeaders());
    String loggingResponseBody = new String(ByteStreams.toByteArray(s),
            StandardCharsets.UTF_8);
    LOG.info(loggingResponseBody); // One param means no format with {}
}

Так что это может быть просто утечка ресурсов. Код кажется хрупким, так как он должен быть уверен, что ответом является текст UTF-8, не превышающий бессмысленных мегабайт.

...