Question

My application correctly runs correctly on a server with 16 processor and 64 GB of Ram. I have multiple process and I try to limit the maximum heap at 8 Gbyte for my process.

My problem is that I have some form of producer-consumer pattern and I have to limit the producing rate or I will run out of memory, because the garbage collection for old generation occurs too rarely.

  • When I monitor my application, I can see that after being running for 4 hours I have spent 7 minutes in ParNEW and 0.775 seconds in ConcurrentMarkSweep.
  • My heap occupation gets up to around 6GB then drops to 1GB then slowly start going up to 6GB then drop down again. The cycles are approximately of 10 minutes

Through JVisualVM I can see that 90% of my memory occupation is given by CMS Old Gen, how can I force the concurrent Mark sweep to run a little bit more frequently?


@PeterLawrey comment is very relevant, since my application runs on the top of an Application server which is designed for event-driven processing and data partitioning, such as Terracotta or Coherence. It is likely that the underlying implementation includes a queueing system for event-processing.

My problem is that limiting the heap size is not a solution, because as I had experienced, instead of having more frequent garbage collection, the application runs out of memory.

Was it helpful?

Solution

I think by setting lower initiating occupancy you can trigger frequent collections.

-XX:CMSInitiatingOccupancyFraction=<nn>

OTHER TIPS

I have to limit the producing rate or I will run out of memory

This would happen if you use unbounded queues. If your producer exceeds the rate of the consumer, the queue can grow without limit until you run out of memory. Limiting the producer can ensure the queues stay at a reasonable size.

A simple way around this is to delay the producer when the queue gets too long.

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);

This will ensure the queue never gets too long but without slowing the producer unnecessarily.

BTW: Using an ArrayBlockingQueue can also reduce the amount of garbage produced compared with Linked Queues.

If you really need an unbounded queue, you can use a library I wrote but it relatively low level. Java Chronicle The producer can be more than the size of the main memory ahead of the consumer. Its only bounded by the size of your disk space.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top