我在具有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变得非常频繁,其他所有线程也变得非常频繁地停止(“停止世界”暂停)。需要帮助找出这种行为的根本原因。
答案 0 :(得分:1)
GC模式看起来像内存泄漏。
查看您的堆转储统计信息,我可以看到3M任务正在线程池中等待执行。
我可以推测,您正在使用具有无限制任务队列的线程池。您的消息入站速率大于系统的处理能力,因此积压工作正在消耗越来越多的内存,最终导致GC死亡。
根据您的情况,您可以限制线程池的队列大小,也可以尝试优化队列任务的内存占用。
限制队列大小将对先前的处理阶段造成压力。如果由计时器驱动的轮询器是线程池的生产者,那么它的作用就是减少轮询器的轮询间隔(因为轮询器会阻止等待队列中的空间)。
仅当您的处理能力平均大于入站任务速率并且问题是由临时增加引起的时,任务内存占用空间的优化才行得通。