1

私はコンプベースのアプリケーションに取り組んでいます。このアプリケーションでは、相互に提供する RMI サービスを介して相互に通信する n 個のコンテナーがあります。特定の時点で、コンテナーに接続されている 1 つの RMI スレッドがメモリ不足エラーのために接続を失っていますが、コンテナーに接続されている他のすべての RMI スレッドは正常に動作しています。

エラーのスタック tarce は次のとおりです。

Exception dispatching call to [655d565c:11f1d5dbae2:-7ffb, -3259564578052694518] in thread "RMI TCP Connection(21)-132.186.96.179" at Wed Jan 28 18:50:37 GMT+05:30 2009: 
java.lang.OutOfMemoryError: Java heap space
    at java.lang.reflect.Array.newArray(Native Method)
    at java.lang.reflect.Array.newInstance(Unknown Source)
    at java.io.ObjectInputStream.readArray(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.defaultReadFields(Unknown Source)
    at java.io.ObjectInputStream.readSerialData(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.defaultReadFields(Unknown Source)
    at java.io.ObjectInputStream.readSerialData(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.readObject(Unknown Source)
    at sun.rmi.server.UnicastRef.unmarshalValue(Unknown Source)
    at sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
    at sun.rmi.transport.Transport$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

この例外を表示するには、RMI 固有のログを有効にする必要がありました。この問題は、この終了したスレッドの各 RMI 呼び出しがコンテナーのヒープにデータを追加するために発生します。そしてある時点で、そのサイズは超過します。

皆さんへの私の質問は、コンテナーのヒープ サイズでメモリが不足している場合、他のスレッドが機能しているのはなぜですか? 何かアイデアがあれば教えてください。

4

2 に答える 2

3

失敗した呼び出しは

java.lang.reflect.Array.newArray(Native Method)

これは、失敗した RMI スレッドが配列を割り当てようとしたことを意味します。残念ながら、割り当てようとした配列の大きさはわかりません。巨大な配列を割り当てようとして失敗した場合、これは他のスレッドを傷つけません。失敗したリクエストについて、行われている他のリクエストよりも多くのメモリ割り当てる必要があるという違いはありますか?

詳しく説明すると...何らかの理由で、この1つのリクエストが500メガ配列を割り当てようとしているとしましょう(そしてヒープに十分なメモリがありません)。まあ、その割り当て要求は失敗します。ただし、ヒープに通常の割り当て要求に対して十分なメモリが残っている限り、他のスレッドが新しいオブジェクトを作成する際に問題が発生することはありません。

于 2009-01-28T13:54:16.643 に答える
3

簡単な答え: 他の操作には、失敗した操作のメモリ要件がないためです。

より長い答えは、スタックトレースを見ることから始まります:

java.lang.OutOfMemoryError: Java heap space at java.lang.reflect.Array.newArray(Native Method) at
java.lang.reflect.Array.newInstance(Unknown Source) at java.io.ObjectInputStream.readArray(Unknown Source) at
java.io.ObjectInputStream.readObject0(Unknown Source) at java.io.ObjectInputStream.defaultReadFields(Unknown
...
sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source) at  

したがって、失敗しているスレッドは、着信要求を処理するために、新しい配列を作成しようとしています。その配列が特に大きい場合、要求ハンドラーはそれを割り当てることができない可能性がありますが、少量のデータを使用する他の要求は問題なく処理されます。

最初の質問は、その配列の大きさはどれくらいですか? これを判断するには、クライアント側にログを記録する必要があります。また、特定のクライアントが非常に大きな配列を送信しようとしている場合は、そのサイズを縮小する必要がある場合があります。

2 番目の質問: 予想される負荷を処理するのに十分なメモリをサーバー JVM に与えましたか? Jave は、プログラムが必要とするメモリ量を伝える必要がある数少ない環境の 1 つであり、デフォルトは非常に小さい (64M だと思います)。-ms および -mx パラメーターを調べて、それを増やす方法を学びます。

于 2009-01-28T13:54:50.950 に答える