【问题标题】:Logging large string causes OutOfMemoryError记录大字符串会导致 OutOfMemoryError
【发布时间】:2019-02-10 07:31:22
【问题描述】:

我的 Spring Boot Web 应用程序连接到许多外部服务,它需要将来自服务的所有请求和响应写入日志文件。

我使用 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);

此代码存在性能问题。它消耗高 CPU,导致高延迟,并且在某些响应消息非常大的情况下,它会在执行 new String(ByteStreams.toByteArray(s), Charset.forName("UTF-8")); 时导致 OutOfMemoryError

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

【问题讨论】:

  • 你可以做类似this的事情
  • 这是一个收集和打印所有服务日志的服务吗?导致OOM的响应体有多大?

标签: java spring performance logging logback


【解决方案1】:

必须关闭 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 文本并且不超过无意义的兆字节。

【讨论】:

  • 你是对的,这是一个资源泄漏问题。谢谢。
猜你喜欢
  • 1970-01-01
  • 2021-01-08
  • 1970-01-01
  • 2018-08-14
  • 2010-09-30
  • 2011-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多