我有一个服务在具有以下配置的 16GB RAM 系统上运行:
-Xms6144M"
-Xmx6144M
-XX:+UseG1GC
-XX:NewSize=1500M
-XX:NewSize=1800M
-XX:MaxNewSize=2100M
-XX:NewRatio=2
-XX:SurvivorRatio=12
-XX:MaxGCPauseMillis=100
-XX:MaxGCPauseMillis=1000
-XX:GCTimeRatio=9
-XX:-UseAdaptiveSizePolicy
-XX:+PrintAdaptiveSizePolicy
它有大约 20 个运行的轮询器,每个轮询器都有大小为 30 的 ThreadPoolExecutor 来处理消息。最初大约 5-6 小时,它能够每秒处理大约 130 条消息。此后,它每秒只能处理大约 40 条消息。
我分析了 GC 日志发现 Full GC 变得非常频繁,并且有超过 1000MB 的数据从年轻代提升到老年代:
查看堆转储,我看到很多线程处于等待状态,类似于:WAITING at sun.misc.Unsafe.park(Native Method)以下类对象获取最多保留大小:
我认为服务及其相关库中可能存在小内存泄漏,随着时间的推移会逐渐累积,因此增加堆大小只会推迟这种情况。或者可能是因为 Full GC 变得非常频繁,所有其他线程都非常频繁地停止(“停止世界”暂停)。需要帮助找出此行为的根本原因。
最佳答案
GC 模式看起来像内存泄漏。
查看您的堆转储统计信息,我可以看到 3M 任务在线程池中等待执行。
我可以推测,您正在使用具有无限任务队列的线程池。您的消息入站速率大于系统的处理能力,因此积压越来越多,消耗更多内存,最终导致 GC 死亡。
根据您的情况,您可以限制线程池的队列大小或尝试优化队列任务的内存占用。
限制队列大小会对之前的处理阶段产生背压。如果它是简单的定时器驱动的轮询器,它是线程池的生产者,效果将是减少轮询间隔(因为轮询器会阻塞等待队列中的空间)。
任务内存占用的优化只有在您的处理能力平均大于入站任务率并且问题是由临时激增引起的情况下才有效。
关于java - 垃圾回收频繁导致服务吞吐量低,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55929669/