【问题标题】:Can logging a huge message (around 90 MB) cause OutOfMemory Error? (Max heap size : 2048M)记录一条巨大的消息(大约 90 MB)会导致 OutOfMemory 错误吗? (最大堆大小:2048M)
【发布时间】:2016-11-08 05:22:27
【问题描述】:

实际上,我通过 RabbitMQ 收到一条很大的消息。 在使用此消息时,我们会记录它。

logger.info("payload: {}", payload);

我在记录器语句行的日志中看到以下异常。

原因:java.lang.OutOfMemoryError: Java heap space 在 java.util.Arrays.copyOf(Arrays.java:3332) 在 java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:137) 在 java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:121) 在 java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:421) 在 java.lang.StringBuffer.append(StringBuffer.java:272) 在 org.apache.log4j.helpers.PatternParser$LiteralPatternConverter.format(PatternParser.java:419) 在 org.apache.log4j.PatternLayout.format(PatternLayout.java:506) 在 org.graylog2.GelfMessageFactory.makeMessage(GelfMessageFactory.java:37) 在 org.graylog2.log.GelfAppender.append(GelfAppender.java:220) 在 org.apache.log4j.AppenderSkeleton.doAppend(AppenderSkeleton.java:251) 在 org.apache.log4j.helpers.AppenderAttachableImpl.appendLoopOnAppenders(AppenderAttachableImpl.java:66) 在 org.apache.log4j.Category.callAppenders(Category.java:206) 在 org.apache.log4j.Category.forcedLog(Category.java:391) 在 org.apache.log4j.Category.log(Category.java:856) 在 org.slf4j.impl.Log4jLoggerAdapter.info(Log4jLoggerAdapter.java:324)

去掉logger语句后,消息处理成功。

那么,我可以确定是记录器导致了OutOfMemoryError 吗? 或者是其他原因导致OutOfMemoryError

堆大小为:2048M

【问题讨论】:

  • 确实看起来像。你的堆空间是多少?尝试使用 -Xmx 参数为 JVM 分配更多堆空间。
  • @SamuelToh IMO 90mb 的日志消息不应该导致错误......但这只是我的意见......
  • @JordiCastilla - 是的,90mb 对于机器来说被认为相对较小,但奇怪的是它在 Arrays.copyOf api 上失败了。要么 OP 的 jvm 真的有一个真正的小堆大小,或者 copyOf api 可能已经进入导致堆耗尽的无限循环?
  • 除了它导致这样的错误之外:将每条消息内容记录为“信息”真的有用吗?我认为这是一个性能瓶颈。不过我想,你不能简单地放弃这条线,所以你可能想要执行大小检查并将日志输出的消息切割成更小的块或只记录第一个块。
  • 这看起来像是一个 XY 问题。没有充分的理由记录整条消息。你为什么这样做?

标签: java


【解决方案1】:

我的应用程序遇到了类似的问题,但它与 spring 有关。在我的代码中,不知何故,一个自动装配的依赖类被标记为抽象,我在服务器启动时开始遇到这个问题。

经过将近一天的研究,我们能够确定问题并加以解决。

【讨论】:

    【解决方案2】:

    在应用程序的启动脚本中,分配给应用程序的初始堆大小的内存参数,以及相同的最大堆大小

    详情请参考this。 用于此目的的启动命令可以以

    之类的内容开头

    java -Xmx12288m

    下面给出了一个示例命令供您参考

    java -Xms1024m -Xmx12288m -XX:MaxPermSize=256m -Dlaser.home=$LASER_HOME -Djob=$job -Djava.library.path=$HADOOP_NATIVE -classpath "$CLASSPATH" $job_runner insights-workflow.xml $job run.date=$runDate env.type=$env
    

    【讨论】:

      【解决方案3】:

      问:那么,我可以确定是记录器导致了 OutOfMemory 错误吗?还是其他原因导致 OutOfMemory 错误?

      答: 根据堆栈跟踪,是的。

      从跟踪中您可以清楚地看到您的 log4j 模块(即 logger 对象)正在尝试执行 copyOf() 操作,但在复制完成之前程序因 OutOfMemoryException 而死。

      关于您通常如何阅读堆栈跟踪,这篇 stackoverflow 帖子可以提供很大帮助。

      How to read and understand the java stack trace?

      引用:

      通常,异常的确切原因在第一行 您的堆栈跟踪,以及有关其原因的更多信息 异常,需要逐步下移,根本原因可以 通常位于堆栈跟踪底部附近的某个位置。

      我通常阅读堆栈跟踪的第一行以确定发生了什么,因为您的原因可能是 OOM 错误,然后我移至最后一行并从下往上阅读以查看哪个 object 或代码区域这可能是导致故障的原因。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-05-05
        • 2012-11-08
        • 2013-03-09
        • 2011-07-18
        • 2012-12-29
        • 2012-04-02
        相关资源
        最近更新 更多