【问题标题】:Default Java Heap Size and Memory Issues it can cause它可能导致的默认 Java 堆大小和内存问题
【发布时间】:2018-08-07 12:48:55
【问题描述】:

我有一个应用程序,它的后端是基于 Java 8 构建的。最近我看到应用程序会自行重启,因为 OOM。通过查看 Docker Container 的退出状态,我了解它是因为 OOM。没有为系统配置 XmxXms 值,因此它应该使用默认的堆大小,如果我的服务器有 4 gigs 的内存应该是 512 MB 左右(我读了一些 SO回答默认堆最大大小是当前内存的 1/8)。设置 XmsXmx 值后,我的应用程序现在可以正常运行,无需重新启动。在设置 XmxXms 值之前,我还尝试将服务器中的内存增加到 7 gig,但这也没有帮助。我想知道的是,当有足够的内存可供应用程序使用时,系统怎么会OOM。
如果应用程序的内存需求增加,默认堆大小是否会自行扩展?如果内存快满了,为什么 GC 没有被触发?

【问题讨论】:

  • 请将堆栈跟踪与您的 OOM 放在一起,因为此异常可能是由于:系统中的 ulimit 太小/整个系统内存不足/非堆内存大小不足。

标签: java java-8 garbage-collection jvm heap-memory


【解决方案1】:

"内存充足时系统怎么会OOM 可用于应用程序。”

这里有两个可能的问题:

  1. 您没有为应用程序的内存需求配置足够的内存,所以您能分享一下您的配置值吗?

  2. 应用程序存在内存泄漏问题,请牢记这一点

来源:http://blog.sysco.no/memory/leak/memory-leak/

Java 的主要优点之一是使用垃圾收集器 这使程序员可以忘记内存管理。那是 不是像 C++ 这样的语言,你必须分配和 自您的代码以来的可用内存。在我在一家大公司的经历中,我看到 内存泄漏问题多次导致不可用或 许多应用程序的性能不佳。

此外,内存泄漏属于一类称为 软件老化问题。软件老化定义了 业绩随着时间的推移逐渐积累 小问题。此类问题中的其他术语是 复兴过程。例如,当 系统必须重新启动,以释放积累的内存 一段时间后的Java虚拟机(JVM)进程(COTRONEO, D 等人,2015)。

基本上,JVM 上的垃圾收集器使用一种机制来重用对象空间,它没有来自根集的任何引用,因此当源代码或配置中出现问题,使对象永远被引用时,很少应用程序将逐渐填满堆,直到达到其限制。

例如,在下图中,只有图中无法访问的对象将被收集,所有可访问的对象(即使是由错误或错误配置生成的对象)都将保存在堆中

来源http://blog.sysco.no/files/guides/JVMGarbageCollectionV1.1.pdf

"如果内存需要,默认堆大小是否会自行扩展 为应用增加?”

答案是否定的,当你的应用程序填满整个新生代时,JVM 将执行一次次要 GC 以释放新生代的对象,而存活下来的对象将被移入幸存者空间一段时间,直到达到某个年龄。当它们(幸存者空间中的对象)足够成熟并且仍然存活时,这些对象将被提升到老年代,当老年代满时,执行一次完整的 GC。因此,您的应用程序似乎在某个时刻保持引用(内存泄漏),整个堆将被活动对象填满,因此 JVM 无法释放它们,并且它没有标志来增加内存以防万一像这样。

“如果内存已满,为什么没有触发 GC?”

在这种情况下,我有一个问题,您如何知道 GC 是否被触发?要调整垃圾收集过程,您必须对此进行测量,以便您可以尝试使用这些标志来获取有关 GC 执行的信息。

-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:/home/user666/gc.log

另外,你可以用这个不错的web来分析日志文件

http://gceasy.io/

但同样重要的是,您可以使用这些标志

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/some/where/your/machine

使用这些标志,您将生成一个堆转储,可以使用内存分析器工具(MAT:https://www.eclipse.org/mat/downloads.php)对其进行分析,以确定应用程序是否存在内存泄漏。

【讨论】:

    【解决方案2】:

    默认的最大堆大小是主内存的 1/4。这假设机器不专用于这一过程。如果是,您可能希望增加最大堆大小。

    注意:堆大小只是堆的大小,它只是 JVM 使用的一个内存区域。它不是总内存消耗。 JVM 需要多少额外内存取决于它在做什么。

    初始大小可以增长到最大值。最大大小不会增长,它是您宁愿进程死亡也不愿再使用的堆大小。

    如果没有更多信息,我会在 4 GB 机器上尝试 3 GB 堆,如果这就是它正在运行的全部内容,然后看看情况如何。你可以在top中监控进程尝试使用多少虚拟内存

    注意:并非所有 OutOfMemoryError(s) 都相同,您需要阅读错误消息以确定问题的实际原因。例如您可能已经用完了线程、perm gen/metaspace 或其他一些低级内存问题。

    【讨论】:

      【解决方案3】:

      如果内存需要,默认堆大小是否会自行扩展 为应用增加?

      是的,但仅限于 -Xmx 中的值(或 JVM 选择的该值的默认值)。

      如果内存已满,为什么没有触发 GC?

      GC 被触发,但它无法收集任何垃圾。您堆中的所有内容都是非垃圾。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-08-20
        • 2013-08-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-20
        • 2017-07-14
        • 2020-08-09
        相关资源
        最近更新 更多