【问题标题】:Java: How to optimize the Heap allocation & Garbage collection?Java:如何优化堆分配和垃圾收集?
【发布时间】:2021-11-15 14:32:52
【问题描述】:

我有一个 spring 批处理应用程序,它消耗约 16GB 内存和 75% 的 CPU(4 核 X2.5Ghz),有时它抛出内存不足异常

我想优化堆分配和垃圾收集并尝试使用以下 JVM 选项来解决内存不足异常

我无法理解其中一些参数,因为我直接从一篇文章中复制粘贴了

JAVA_OPTS="-server -Xmx20480m -Xms512m -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSClassUnloadingEnabled -XX:+CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=30 -XX:+CMSIncrementalMode -XX:+CMSIncrementalPacing -XX:ParallelCMSThreads=2 -XX:+UseCMSCompactAtFullCollection -XX:+DisableExplicitGC -XX: MaxHeapFreeRatio=70 -XX:MinHeapFreeRatio=40 -XX:MaxTenuringThreshold=0 -XX:NewSize=450m -XX:MaxNewSize=650m"

真的会优化堆分配和垃圾收集并解决内存不足异常吗?

【问题讨论】:

  • 首先是分析一个java heap dump。特别是批次可能会膨胀,应该保持整洁。执行 SonarLint 以获得真正容易的维修,并执行 profiling 以解决结构瓶颈。更快的批次和更少的资源比人们想象的更重要。
  • drop CMS,老了,没人支持,在jdk-14中被删除了。

标签: java spring jvm spring-batch heap-memory


【解决方案1】:
  • 当您使用过多的“字符串”对象或一次又一次地更新这些字符串时,也会发生这种情况。
  • 字符串存储在哈希字符串池中,该池位于堆空间中。当您操作字符串时,会形成一个新字符串并将其存储在不同的池(散列池)中,但在垃圾收集器执行此操作之前不会删除原始字符串。
  • 如果我们使用 StringBuilder 或 StringBuffer(两者都是可变的,不像字符串),空间会得到更好的利用。

阅读有关字符串不变性的更多信息,以及为什么当您需要执行大量字符串操作时应该首选 stringbuilder。

StringBuilder-StringBuffer-Strings in java Why strings are immutable in java?

【讨论】:

    【解决方案2】:

    首先,您需要在进程抛出 OOM 错误时对其进行堆转储。您可以通过添加-XX:+HeapDumpOnOutOfMemoryError JVM 选项来做到这一点。当您拥有堆转储后,请尝试使用以下任何工具来分析您的堆转储。找到内存中增长的对象,然后对其进行优化。堆转储分析工具有:

    1. Eclipse Memory Analyzer
    2. Heap Hero
    3. jxray

    【讨论】:

      【解决方案3】:

      当没有足够的空间在 Java 堆上分配对象时,或者如果 Java 进程花费超过 98% 的时间进行垃圾收集并且回收不到 2% 的堆时,通常会引发此错误并且在最近 5 个垃圾回收周期中一直在进行。

      我会首先使用 Java 分析器来确定哪些方法在堆上分配大量对象,并确保在不需要它们之后不再引用它们。如果这不能解决问题并且我已经确认我需要所有对象,那么另一个选择是增加程序的最大堆大小。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-30
        • 2012-03-06
        • 1970-01-01
        • 2010-12-13
        相关资源
        最近更新 更多