0

Producer-Consumer シナリオで ConcurrentLinkedQueue を使用しています。私のプロデューサーは、私のアプリケーションのすべてのメソッドによって呼び出されるシングルトンです: Producer.getInstance().add("foo"); add() メソッドは ConcurrentLinkedQueue offer メソッドを呼び出します。

public void add(String message) {
    myQueue.offer(message);
}

それ以外の場合は、Consumer を別のスレッドで実行し、Producer 内の ConcurrentLinkedQueue で poll メソッドを呼び出すだけです。

編集:

if ((buffer = myQueue.poll()) != null) { } の間にコードを追加します

CRActiveMQProducer は、ActiveMQ サーバーへの接続を初期化し、send() メソッドでメッセージを送信するシングルトンです。

private StringBuffer stringBuffer = new StringBuffer();

public void run() {
    while(condition) {
        String buffer = null;
        if ((buffer = myQueue.poll()) != null) {
            stringBuffer.append(buffer);
            numberMessage++;
            if (numberMessage >= 10000) {
                CRActiveMQProducer.getInstance().send(stringBuffer.toString());
                stringBuffer = stringBuffer.delete(0, stringBuffer.length());
                numberMessage = 0L;
            }
        }
    }
} 

Producer の add() メソッドを 5000 万回呼び出します (これは膨大ですが、実行すべき呼び出し回数のわずか 2.5% です)。

とにかく、OutOfMemory 例外が発生しました。VisualVM でヒープ ダンプを読み込もうとすると、この OOM は膨大な数の ConcurrentLinkedQueue$Node インスタンス (30Millions 以上) によって引き起こされたことがわかりました。offer() または poll() メソッド呼び出しごとに新しいノードがあると思いますが、100% 確実ではありません (完全なヒープ ダンプを読み込めません...)。

これは ConcurrentLinkedQueue の通常の動作だと思いますか? それとも私が何か間違ったことをしているのですか?ありがとう!

4

2 に答える 2

0

キューは明らかに、キューに入れたすべての要素を格納する必要があり、相互にリンクされたノードを使用してそれを行います。これがリンクされたキューの原則です。あなたのプロデューサーはitelsをあまりにも速く生成し、コンシューマーはそれらを消費する時間がないので、結局、あなたはOOMになってしまいます。

バインドされたBlockingQueueの使用を検討する必要があります。キューに含まれる要素が多すぎると、プロデューサースレッドが強制的にブロックされ、OOMが回避されます。

于 2012-07-10T22:01:53.857 に答える
0

カップルの提案:

  1. アプリケーションにさらに多くのメモリを追加します。次のようなものを試してください-Xmx2g
  2. キューから読み取るスレッドを追加してみてください
  3. 「バッファで何かをする」をできるだけ速くする
  4. 「バッファーで何かをする」ことを独自のスレッドにスピンオフして (おそらくスレッドプールを使用して)、キューからの読み取りをブロックしないようにします。

リーダー サービス内のすべての時間を計測して、所要時間を確認しましたか? 読み取るよりも速くキューに入れている場合は、リーダーを高速化する方法を見つける必要があります。メモリ不足は、実際の問題の副作用にすぎません。問題は、キューに入れられた作業を十分に速く処理していないことです。

于 2012-07-11T00:22:54.743 に答える