我的应用程序在具有16个处理器和64 GB Ram的服务器上正确运行。我有多个进程,我尝试将最大堆限制为8 GB,用于我的进程。
我的问题是我有某种形式的生产者 - 消费者模式,我必须限制生产率,否则我将耗尽内存,因为老一代的垃圾收集很少发生。
通过JVisualVM我可以看到我的内存占用的90%是由CMS Old Gen给出的,我如何强制并发Mark扫描更频繁地运行?
@PeterLawrey评论非常相关,因为我的应用程序运行在应用程序服务器的顶部,该服务器专为事件驱动的处理和数据分区而设计,例如Terracotta或Coherence。底层实现可能包括用于事件处理的排队系统。
我的问题是限制堆大小不是解决方案,因为正如我所经历的那样,应用程序内存不足,而不是更频繁地进行垃圾收集。
答案 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>