このページで解決しない高度なJavaのシステム障害はJaTSにお任せください

Trouble 9: RMIに関する問題



<Q9-1>RMIサーバオブジェクトがクライアントからのリクエスト処理中に、OutOfMemoryErrorを引き起こしてもサーバプロセスがEXITしません。

しかも、オブジェクトリファレンスは引き続き参照可能で、リクエストも受け付けるが、返り値オブジェクトが正常に返ってきません。

<発生環境>
OS Solaris2.6
JDK JRE1.3
Vender Sun
<A9-1>
RMIサーバオブジェクトのRMIインタフェース実装部を全てtry節で囲み、Throwableをcatchしてエラーハンドリング(この場合はSystem.exit)するようにすることで解決できます。
Page Top

<Q9-2>リモートメソッド呼び出しにおいて、ローカルで身に覚えのないRuntimeExceptionやOutOfMemoryErrorが発生してしまいます。

しかし、ローカルのプログラムのヒープ使用状況には問題はありませんでした。

<発生環境>
OS RedHatLinux6.2 SMP
JDK JDK1.3
Vender Sun
<A9-2>
原因として、リモートメソッドのサーバ実装でRuntimeExceptionやOutOfMemoryErrorが発生している可能性が高いです。
サーバ実装で発生したNullPointerExceptionはRemoteExceptionにきれいにネストされて届くとは限りません。
Page Top

<Q9-3>Naming.bind()、Naming.lookup()でNullPointerExceptionが発生してしまいます。


<発生環境>
OS RedHatLinux6.1/6.2 Solaris7
JDK JDK1.3
Vender Sun
<A9-3>
該当メソッドの引数に渡すURLをrmi://hostname/objNameの形式にすることで解決できます。不完全なURLを引数に渡した場合、MalformedURLExceptionではなくNullPointerExceptionが発生する場合があります。
Page Top

<Q9-4>Naming.bind()の引数に他のホストをあらわすURLを渡すと、rmiregistryを正しく実行しているのに例外が発生してbind()できません。


<発生環境>
OS RedHatLinux6.1/6.2
JDK JDK1.2/JDK1.3
Vender Sun/IBM(1.3のみ)
<A9-4>
JDKに付属するrmiregistryの仕様です。他ホストのリモートオブジェクトをbind()することはできません。
Page Top

<Q9-5>WebLogicでrmiを動かす際にWebLogicのクラスが無いと表示されます。


<発生環境>
OS Windows2000
JDK JDK1.3.1
Vender Sun
<A9-5>
WebLogicのJNDIを利用する場合など、weblogic/libのjarファイルだけではなく、classes以下のクラスも利用されるので、classes以下を配置する必要があります。
Page Top

<Q9-6>RMI通信時に、jarファイルの中に該当クラスが含まれているにもかかわらず、クラスローディングに失敗し、java.rmi.UnmarshalExceptionが発生してしまいます。

RMI通信時に、jarファイルの中に該当クラスが含まれているにもかかわらず、クラスローディングに失敗し、java.rmi.UnmarshalExceptionが発生してしまいます。

<発生環境>
OS RedHatLinux6.2 SMP
JDK JDK1.3.0
Vender Sun
<A9-6>
適切な解決策は不明です。
クラスパス上に、展開したclassファイルを置いたところ、ローディングできました。
プラットフォーム、JDKのバージョンは異なりますが、酷似した問題が、BugParade:4250650に存在しています。

参考URL:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4250650
Page Top

<Q9-7>JDK1.3で動作していたプログラムをJDK1.4で実行したところ、Naming.bind()で例外が発生しました。

以下の例外が発生しました。

java.net.MalformedURLException: invalid URL string: 
rmi://192.0.0.1:21000/Some Host
    at java.rmi.Naming.parseURL(Naming.java:266)
    at java.rmi.Naming.bind(Naming.java:104)

    - 中略 -
Caused by: java.net.URISyntaxException: 
    Illegal character in path at index 26: 
    rmi://192.0.0.1:21000/Some Host
    at java.net.URI$Parser.fail(URI.java:2701)

    - 後略 -

<発生環境>
OS Solaris8
JDK JDK1.4
Vender Sun
<A9-7>
URLに空白を含んでいる為です。

JDK1.3.1までは、エスケープされていない空白を含んだURLをjava.net.URLクラスは許していました。
しかし、JDK1.4から空白を含んだURLに対して、Namingクラスが例外をスローするように修正されました。
(エスケープしていない空白文字はRFC2396に違反します。)

問題の詳細は、BugParade:4641504を参照してください。

参考URL:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4641504
Page Top

<Q9-8>JMSを利用しているプロジェクトにて、何度もフルGCが実行されてしまいます。

JMSのメソッドを呼び出すたびに、GCが実行されてしまいますが、JMSの呼び出し時には、必ずGCが発生するのでしょうか。

また、Javaの起動引数に "-XX:+DisableExplicitGC" オプションをつけてフルGC(ガベージコレクション)が発生しないようにすると、JMSでメモリリークが発生してしまわないでしょうか。

<発生環境>
JDK Java 1.5.x
AP JBoss3.2.7
<A9-8>
フルGCを実行しているのは、JMSが利用しているRMIです。
RMIはGCを定期的に(1分毎に)実行しており、パフォーマンス低下の原因となるため、Bug Databaseにも登録されています。

参考URL:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6200091

Java6ではSystem.gc()の頻度が1時間になっているため、同様の問題は発生しません。

また、BugDatabaseでは、それ以前のバージョンについては起動オプションを指定し、10分~1時間程度にすることが推奨されています。
なお、-XX:+DisableExplicitGCを付けても、JMSではメモリリークは発生しません。
Page Top

<Q9-9>RMI通信でSSLの設定を行ったところ、Memoryが大量に消費され、アプリケーションが停止します。

RMI通信を行っているアプリケーションに対して、
RMIServerSocketFactoryとRMIClientSocketFactoryをオーバライドしたクラスを作成し、
SSL通信を行えるようにしたところ、
Memoryが大量に消費され、アプリケーションが停止します。

<発生環境>
OS Any
JDK JDK5.0以降
Vender Sun
<A9-9>
SSL通信用に作成した、RMIClientSocketFactoryの
equalsメソッドとhashCodeメソッドに問題がある可能性があります。

RMI通信では、クライアントからの通信時に、
サーバからクライアントにSocketFactoryをコピーします。

その際、同一のClientSocketFactoryが既にクライアントにある場合は、
コピー処理を行わず、そのClientSocketFactoryを通信に使用します。

ClientSocketFactoryの同一性は、equals、hashCodeメソッドで判定するため、
これらのメソッドが定義されていないと、毎回別のオブジェクトと見なされ、
通信の度に新しいClientSocketFactoryが生成されます。

さらに、ClientSocketFactoryに1対1でRenewCleanというスレッドが作成されるため、
通信の度にRenewCleanスレッドが作成され、使用メモリも増え続けてしまいます。

この問題は、Java Bug Databaseにも記載されています。


参考URL:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5053529

[対策]
RMIClientSocketFactoryのhashCodeメソッドとequalsメソッドを実装してください。
※このことは、RMIClienctSocketFactoryのJavaDocにも記述されています。

同様に、RMIServerSocketFactoryのJavaDocでも、
hashCodeメソッドとequalsメソッドを実装することが勧められているため、
実装が必要です。

hashCodeメソッドとequlasメソッドの例を以下に記載します。
public int hashCode() {
  final int prime = 31;
  int result = 1;
  result = prime * result + port;
  return result;
}

public boolean equals(Object obj) {
  if (this == obj)
    return true;
  if (obj == null)
    return false;
  if (getClass() != obj.getClass())
    return false;
  final SampleServerSocketFactory other = 
                   (SampleServerSocketFactory) obj;
  if (port != other.port)
    return false;
  return true;
}

Page Top

注意:本文書の内容に誤りがあり、またこの文書によって不利益を被っても、
Acroquest Technology 株式会社は一切関知いたしません。

  • 現象別Index
  • 原因別Index

Find Bugsバグ詳細

Find Bugs Bug Descriptions日本語版

RSSで更新情報を取得する

RSSとは、ホームページの更新情報を配信する為のフォーマットです。
RSSを利用すると、登録したページの情報が更新された場合に、更新情報を自動的に受け取る事ができます。

詳細

弊社小森が執筆致しました

Javaでオブジェクト指向開発

Javaプログラミング言語習得において、新人プログラマーの最初の障害は「オブジェクト指向の壁」です。
本書は、Javaのソフトウェア開発を中心に事業を発展させてきたAcroquest社の新人教育セミナーを加筆・書籍化したもので、大卒の新人に対して、ゼロからJava言語を教えてきた実績をフィードバックしています。

メールマガジン配信中

Javaトラブルシューティングのメルマガをはじめました!是非ご購読ください

詳細