并发Mark Sweep Collection不常发生

时间:2012-09-17 14:48:14

标签: java garbage-collection concurrent-mark-sweep

我的应用程序在具有16个处理器和64 GB Ram的服务器上正确运行。我有多个进程,我尝试将最大堆限制为8 GB,用于我的进程。

我的问题是我有某种形式的生产者 - 消费者模式,我必须限制生产率,否则我将耗尽内存,因为老一代的垃圾收集很少发生。

  • 当我监视我的应用程序时,我可以看到在运行4小时后,我在ParNEW中花了7分钟,在ConcurrentMarkSweep中花了0.775秒。
  • 我的堆占用率上升到6GB左右然后下降到1GB然后慢慢开始上升到6GB然后再次下降。周期约为10分钟

通过JVisualVM我可以看到我的内存占用的90%是由CMS Old Gen给出的,我如何强制并发Mark扫描更频繁地运行?


@PeterLawrey评论非常相关,因为我的应用程序运行在应用程序服务器的顶部,该服务器专为事件驱动的处理和数据分区而设计,例如Terracotta或Coherence。底层实现可能包括用于事件处理的排队系统。

我的问题是限制堆大小不是解决方案,因为正如我所经历的那样,应用程序内存不足,而不是更频繁地进行垃圾收集。

2 个答案:

答案 0 :(得分:3)

  

我必须限制生产率,否则我将耗尽内存

如果使用无界队列,就会发生这种情况。如果您的生产者超过了消费者的比率,那么在您的内存不足之前,队列可以无限制地增长。限制生产者可以确保队列保持合理的大小。

解决这个问题的一个简单方法是在队列过长时延迟生产者。

private final BlockingQueue<Task> tasks = new ArrayBlockingQueue<Task>(1000);

// the producer slows when the queue length gets too long.
tasks.offer(newTask, 1, TimeUnit.HOURS);

这将确保队列永远不会太长,但不会不必要地减慢生产者的速度。

BTW:使用ArrayBlockingQueue还可以减少与链接队列相比产生的垃圾量。

如果你真的需要一个无界的队列,你可以使用我写的库,但它的级别相对较低。 Java Chronicle生产者可以超过消费者之前的主要内存大小。它只受磁盘空间大小的限制。

答案 1 :(得分:2)

我认为通过设置较低的initiating occupancy,您可以触发频繁的收集。

-XX:CMSInitiatingOccupancyFraction=<nn>