2

私のアプリケーションは、16 個のプロセッサと 64 GB の RAM を搭載したサーバーで正しく動作します。複数のプロセスがあり、プロセスの最大ヒープを 8 GB に制限しようとしています。

私の問題は、何らかの形の生産者と消費者のパターンがあり、生産速度を制限する必要があることです。そうしないと、古い世代のガベージ コレクションがほとんど発生しないため、メモリが不足します。

  • アプリケーションを監視すると、4 時間実行した後、ParNEW で 7 分、ConcurrentMarkSweep で 0.775 秒を費やしたことがわかります。
  • 私のヒープ占有率は最大で約 6GB になり、その後 1GB まで低下し、ゆっくりと 6GB まで上昇してから再び低下します。サイクルは約10分です

JVisualVM を介して、メモリ占有の 90% が CMS Old Gen によって与えられていることがわかります。どうすれば、並行マーク スイープをもう少し頻繁に実行するように強制できますか?


@PeterLawrey のコメントは非常に関連性があります。私のアプリケーションは、Terracotta や Coherence などのイベント駆動型処理とデータ パーティション分割用に設計されたアプリケーション サーバー上で実行されるからです。基礎となる実装には、イベント処理用のキューイング システムが含まれている可能性があります。

私の問題は、ヒープ サイズを制限することは解決策ではないということです。私が経験したように、より頻繁にガベージ コレクションを行う代わりに、アプリケーションがメモリ不足になるからです。

4

2 に答える 2

3

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.

于 2012-09-17T15:00:38.117 に答える
2

開始時の占有率を低く設定することで、頻繁な収集をトリガーできると思います。

-XX:CMSInitiatingOccupancyFraction=<nn>
于 2012-09-17T14:51:51.693 に答える