1

Javaソケットオブジェクト通信でメモリリークの問題が発生しました。

これは私の送信スレッドです。

    // create a new thread to send the packet
@Override
public synchronized void run() {

    if(!genericSocket.isConnected()){
        if(logger.isEnabled())
            logger.logMessage(PFLogging.LEVEL_WARN, "Socket is close");
        return;
    }

    int retry = 0;
    boolean packetSent = false;

    synchronized (objWriter) {
        while ((retry < RETRY) && (!packetSent) && (genericSocket.isConnected())) {
            try {
                objWriter.writeObject(bean);

                objWriter.flush();



                // Try until the cache is reset and the memory is free
                /*
                boolean resetDone = false;
                while(!resetDone) {
                    try {
                        objWriter.reset();
                        resetDone = true;
                    } catch (IOException r) {
                        Thread.sleep(1);
                    }
                }
                */

                // No error and packet sent
                continuousError = 0;
                packetSent = true;
            } catch (Exception e) {
                continuousError++;

                if(logger.isEnabled())
                    logger.logMessage(PFLogging.LEVEL_ERROR, "Continuous Error [" + continuousError + "] sending message [" + e.getMessage() + "," + e.getCause() + "]");

                // control the number of continuous errors
                if(continuousError >= CONTINUOUS_ERROR) {
                    if(logger.isEnabled())
                        logger.logMessage(PFLogging.LEVEL_WARN, "I close the socket");
                    genericSocket.disconnect();
                }

                // next time is the time!
                retry++;
            }
        }
    }
}

キャッシュ、1ミリ秒あたり約iパケットを送信すると、成長します!

コメント部分を追加するとキャッシュはクリーンになりますが、非同期の長いメッセージ(約3000文字)を送信する必要がある場合は、他のメッセージが失われることがわかります。

キャッシュをリセットせずにクリーンアップする別の方法はありますか?

4

4 に答える 4

2

ObjectOutputStream.reset() は、ローカル ハッシュ テーブルをクリアする唯一の手段であるため、回避できません。reset() で何が起こるかの詳細については、ObjectOutputStream の Java ソース コードを参照してください。そうしないと、最終的に OutOfMemoryError が発生します。

しかし、次のような機能を非常にうまく実装できます

private void writeObject(Object obj, ObjectOutputStream oos) throws IOException
    {
        synchronized(oos)
        {
            oos.writeObject(obj);
            oos.flush();
            oos.reset();
        }
    }

ただし、ObjectOutputStream へのすべての書き込みがこのメソッドを介して行われるようにする必要があります。

于 2012-09-20T18:00:27.830 に答える
1

私が見つけた唯一の解決策は、最初に送信スレッドを開始して、スレッドプールが空かどうかを確認し、その場合は出力ストリームをリセットすることです。これを確認するために、一晩中ソフトウェアを実行しました。

皆さんありがとう!

マッテオ

于 2012-09-20T13:22:46.093 に答える
0

定期的に使用ObjectOutputStream.reset()して、ストリームのオブジェクト キャッシュをクリアします。

すべてのオブジェクトを送信した後に使用することもできます。;)

于 2012-09-20T09:16:59.223 に答える
0

チャオ:)、

ObjectOutputStream.flush() の後、安全に ObjectOutputStream.reset() を使用できます

同期された(objWriter)ステートメントを使用せずに、別のスレッドのどこかでobjWriterを使用していない限り。この場合、IMHO がスレッドで objWriter を使用するのが最善の方法です。同期されたキューからオブジェクトを送信します (Queue サブクラスhttp://docs.oracle.com/javase/1.5.0/docs/api/を参照)。 java/util/Queue.html、たとえばhttp://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ConcurrentLinkedQueue.html )は、他のスレッドから入力されます(覚えておいてください) object.clone() を使用してください。objcet 自体は同期化されていないため、書き込み中またはキュー内にあるときに他のスレッドによって変更される可能性があります! クローンを作成すると、クローンは安全なコピーになります)。

そうすれば、スレッドと ObjectOutputStream の間のデータフローが既に同期されているため、同期されたステートメントは必要なく、エラーが発生しにくくなります。

于 2012-09-20T10:00:17.277 に答える