使用G1垃圾收集器时出现高内存使用问题

3
我们最近使用以下配置测试了G1垃圾收集器:
-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+UseG1GC -XX:MaxGCPauseMillis=1250 -XX:+PrintTenuringDistribution -Xloggc:${logdir}/gc-$(date +%Y_%m_%d-%H_%M).log -XX:+UseStringDeduplication -XX:+PrintStringDeduplicationStatistics -XX:+PrintPromotionFailure -XX:+PrintAdaptiveSizePolicy -XX:+PrintHeapAtGC -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M -XX:+UnlockExperimentalVMOptions -XX:G1NewSizePercent=15 -XX:ParallelGCThreads=8 -XX:+ParallelRefProcEnabled -XX:G1HeapRegionSize=8M JAVA_OPTS_HEAP: -Xms16g -Xmx16g
我们最近遇到一个问题,即在具有48 GB RAM的计算机上运行两个使用以上配置的Java进程,这两个进程都会消耗大约20-22 GB的RAM(其余内存由几个小进程占用),从而填满整个RAM,然后触发磁盘交换,最终导致OOM并杀死进程。
这似乎令人担忧,因为NMT没有以有意义的方式报告此内存使用情况,我们也无法从GC日志中获得有关此使用情况的任何线索。在NMT统计数据中,应用程序内存不足16G,元空间使用率不足1G。
我们尝试将maxMetaSpaceSize设置为2G,但这也没有帮助。当进程运行数天时,RAM使用似乎会无限增长。
从其他问题中可以看出,G1垃圾收集器确实倾向于消耗更多的内存,但磁盘交换是一个令人担忧的问题。请问有人能提供一些指针,以解决此问题吗?

这个问题有任何更新吗? - Onki
目前为止,我们还没有找到这个问题的根本原因。 - Anish Gupta
我们遇到了类似的情况。系统运行了几天都很好,堆消耗15%,总内存消耗30%。然后,在几分钟内,JVM开始消耗所有可用的内存(总共10G),然后开始交换。堆保持不变,但监视器变得混乱,因为系统无法响应,像一个疯子一样分页。这是生产流量,然后有一天,咔嚓一声!飞向月球,爱丽丝!我们正在切换回去,看看接下来几天会发生什么。 - Will Hartung
2个回答

5

针对长评论,我将其作为答案提交。

一篇好的文章解释了为什么Java进程可能会消耗比-Xmx更多的内存。根据提供的信息,我认为这也是您的情况。

对于G1,有一个OBE(使用G1垃圾收集器入门),详细介绍了G1GC的功能。请查看G1的推荐用例。也许您不会从使用G1中受益。

引用自OBE(Oracle By Example):

如果您使用CMS或ParallelOldGC,并且您的应用程序没有经历长时间的垃圾收集暂停,则可以继续使用当前的收集器。


我们确实通过使用G1获得了性能优势。我们的吞吐量更好,不再频繁发生全局垃圾回收(CMS几乎每天都会发生),因为堆被严重碎片化。根据测试结果,G1适合我们的需求。 - Anish Gupta
@AnishGupta 那么你需要分析GC日志文件(这是一篇旧的帖子,可能会在开始时有所帮助https://blogs.oracle.com/poonam/understanding-g1-gc-logs),以查看是否可以调整它以消耗更少的内存,而不降低更好的吞吐量或增加更多的RAM(如果可能的话)。 - SubOptimal

2

这里可以找到G1、Parallel、ConcMarkSweep、Serial和Shenandoah垃圾回收器在缩放和资源消耗方面的测试结果,以及一些关于如何设置来改善结果的建议。因此,您可以选择最适合您项目并减少内存使用的垃圾回收器。


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