Java老年代会持续增长直到Tomcat重启

3

我在多个服务器上安装了JDK 8,堆大小不断增加,直到达到90%并导致应用程序失败。在此期间,多个GC运行,但老年代仍然保持增长,直到应用程序失败。目前的解决方法是重新启动Tomcat。我的服务器有15GB RAM和4核CPU。我的Java设置如下:

-Xms12036M -Xmx12036M -Xmn800M 

这些值有什么建议吗?我原以为GC会处理它,但似乎老年代没有。我是Java的新手,不确定这是否表示内存泄漏或GC没有执行此操作。


3
我会检查您的应用程序是否存在泄漏。您尝试过使用分析器吗? - jgitter
4个回答

2

我认为您的参数没有问题。建议检查您的代码中是否存在内存泄漏。使用分析工具是一个好主意,但您也可以寻找泄漏模式。这里有一个非常好的收集资料:Creating a memory leak with Java


2
首先使用JStacks/JMaps、线程转储和内存分析工具检查内存泄漏问题。如果您的系统中没有内存泄漏,那么您需要优化垃圾回收器算法。
Java提供了不同类型的垃圾回收器。
查看各种GC算法的优点和缺点:GC算法 1.串行收集器:串行收集器是最简单的收集器,主要针对单线程环境而设计,您可能不会使用它。
2.并行/吞吐量收集器:其最大优点是使用多个线程扫描和压缩堆。并行收集器的缺点是在执行小型或完整的GC收集时会停止应用程序线程。
3.CMS收集器:该算法使用多个线程(“并发”)扫描堆(“标记”)以寻找可以回收的未使用对象(“清除”)。如果增加老年代的大小(或整个堆),或者为收集器分配更多后台线程,则效率会更高。它使用更多的CPU来提供应用程序更高的连续吞吐量。
4.G1收集器:JDK 7更新4中引入的Garbage First收集器(G1)旨在更好地支持大于4GB的堆。 G1收集器利用多个后台线程扫描堆,将其划分为区域,跨度从1MB到32MB(取决于堆的大小)。使用-XX:+ UseG1GC标志。
如果您正在使用G1收集器,则必须优化区域大小参数。如果您的堆大小为15 GB,则区域大小应为(15 GB / 2048)MB,约为7 MB。不要在New Gen Size上进行更多实验。由于此算法在默认值下提供最佳性能,因此可以保持默认设置。
查看此文章:https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/g1_gc_tuning.html

非常感谢大家的反馈,你们提供的所有意见都非常好。 - raindrop

1

JVM的垃圾回收仅负责清理主程序没有引用的对象(包括“引用循环”)。

如果堆中有许多对象不能被GC收集,则可能导致OOM,有两种可能性:

  1. 这些对象在逻辑上是程序所需的:
    您需要添加内存资源或更改程序流程以避免使用大量内存资源。

  2. 这些对象在逻辑上不再需要,但仍被主程序引用 (例如,对象不再需要,但未从列表中删除): 这是Java中的内存泄漏问题,是一个bug,您必须在程序中修复它。

尝试使用一些分析工具或跟踪代码以确定是否存在内存泄漏问题。


0

-Xmn800M(800MB 的年轻代)对于 12GB 堆来说似乎是一个相当低的值。考虑直接取消该参数,并保留 -Xms12036M -Xmx12036M 参数。

请注意,您的老年代将继续增长,直到进行完整 GC。您会有很多次小的 GC,在前面的 800MB 上进行 GC,但不会在其余的 11.2GB 上进行 GC。因此,请尝试使用 Eclipse Memory Analysis 工具 比较堆转储。另外,尝试获取几个不同的堆转储。关注一下大小单调递增的对象。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接