代码之家  ›  专栏  ›  技术社区  ›  asinkxcoswt

记录大字符串会导致OutOfMemoryError

  •  1
  • asinkxcoswt  · 技术社区  · 6 年前

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

    我对日志引擎使用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 回复  |  直到 6 年前
        1
  •  2
  •   Joop Eggen    6 年前

    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文本,并且不超过毫无意义的兆字节。