20

Jetty によって実行される非常に小さな Web サービス (1,000 行未満のコード) があります。ストレステストの段階でも、サービスは常に正常に機能しました。ただし、13 日間のアップタイムの後、同じ日に 2 つのノードで ClassNotFoundException が発生しました。

奇妙なことは、見つからなかったクラスが既に存在していたことです (これはスタートアップ ルーチンの一部であり、以前の要求を処理するために常に使用されていました)。実際、プロセスを再起動するだけで問題は解決しました。両方のノードは別々のマシンにあり、互いに独立しています。1 つの JMS 接続を除いて、外部リソースに依存しません。

報告された問題のほとんどは、Java プロセスの起動中にクラス パスにクラスが見つからないことに関連しているため、これをグーグルで検索しているときに関連情報を見つけることができませんでした。これは私たちのケースではありません。JVM メモリを何らかの形で破壊するメモリ リークが発生した可能性があると思われますが、2 つのノードでほぼ同時に同じ問題が発生した理由を説明することはできません。過去 5 日間、JVM モニターとメモリ リーク アナライザーを接続して集中的なストレス テストを実行してきましたが、すべて問題ないようです。このテストでは、プロセス メモリを 2GB から 512MB に減らしました。

詳細:

  • Java HotSpot(TM) 64 ビット サーバー VM の使用 (ビルド 16.3-b01、混合モード)
  • jetty-runner-8.1.0.RC5.jar の使用
  • 元のコマンドライン: java -Xmx2048M -jar jetty-runner-8.1.0.RC5.jar --port 5000 webapp.war
  • Intel Xeon E5-2680 8 コア (x2) + 16GB RAM
  • レッドハット エンタープライズ リナックス 6
  • 使用中のフレームワーク: JBoss Resteasy、Spring IoC、Guava。

JVM が以前にロードされたクラスの存在を突然「忘れ」、再度ロードできなくなる原因について、アイデアを提供していただけませんか?

Caused by: java.lang.ClassNotFoundException: com.a.b.c.SomeClass
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202) ~[na:1.6.0_37]
    at java.security.AccessController.doPrivileged(Native Method) ~[na:1.6.0_37]
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190) ~[na:1.6.0_37]
    at java.lang.ClassLoader.loadClass(ClassLoader.java:306) ~[na:1.6.0_37]
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301) ~[na:1.6.0_37]
    at java.lang.ClassLoader.loadClass(ClassLoader.java:247) ~[na:1.6.0_37]
    at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:424) ~[na:na]
    at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:377) ~[na:na]
    at java.lang.Class.forName0(Native Method) ~[na:1.6.0_37]
    at java.lang.Class.forName(Class.java:247) ~[na:1.6.0_37]
    at sun.reflect.generics.factory.CoreReflectionFactory.makeNamedType(CoreReflectionFactory.java:95) ~[na:1.6.0_37]
    at sun.reflect.generics.visitor.Reifier.visitClassTypeSignature(Reifier.java:107) ~[na:1.6.0_37]
    at sun.reflect.generics.tree.ClassTypeSignature.accept(ClassTypeSignature.java:31) ~[na:1.6.0_37]
    at sun.reflect.annotation.AnnotationParser.parseSig(AnnotationParser.java:370) ~[na:1.6.0_37]
    at sun.reflect.annotation.AnnotationParser.parseClassValue(AnnotationParser.java:351) ~[na:1.6.0_37]
    at sun.reflect.annotation.AnnotationParser.parseMemberValue(AnnotationParser.java:280) ~[na:1.6.0_37]
    at sun.reflect.annotation.AnnotationParser.parseAnnotation(AnnotationParser.java:222) ~[na:1.6.0_37]
    at sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:69) ~[na:1.6.0_37]
    at sun.reflect.annotation.AnnotationParser.parseAnnotations(AnnotationParser.java:52) ~[na:1.6.0_37]
    at java.lang.reflect.Field.declaredAnnotations(Field.java:1014) ~[na:1.6.0_37]
    at java.lang.reflect.Field.getDeclaredAnnotations(Field.java:1007) ~[na:1.6.0_37]

編集:

WinでNFSマウントを使用しているときに、JVMがクラスをアンロードすることを決定し、必要に応じて再ロードする可能性があると誰かが私に言いました。このプロセスの途中で NFS 接続が切断された場合、ファイル ハンドルは無効になり、再ロードは同様のスタック トレースで失敗します。私たちの場合、Linux を使用しており、関連するすべてのファイルは同じマウント (ローカル ハードディスク) にあります。さらにテストを行うために、Jetty 一時ディレクトリに CD を作成し、特定のサービス クラスでよく知られているディレクトリを手動で削除しました。JVM がそれをアンロードしてからクラス ディレクトリから再ロードしようとすると、失敗します。これは元の問題を説明するものではありませんが、より多くの情報がテーブルに表示される可能性があります...

4

2 に答える 2

8

これが起こっていることです:

  1. 上記の cmd を使用してサービスを開始すると、Jetty は「/tmp」の下にサブディレクトリを作成します。このサブディレクトリには、JVM によってロードされたアプリケーション クラスとリソースが保持されます。
  2. 非アクティブな期間 (特定のシナリオでは 13 ~ 20 日間) が経過すると、そのディレクトリは表示されなくなります。その結果、JVM はファイルをロードできません。JVM がこのエラーの前にクラスをアンロードしたかどうか、または *.class ファイルを再読み込みしようとした理由はまだ正確にはわかっていません。ソース コードを調べてこれについて学ぶのは興味深いことですが、それは短期的な ToDo リストにはありません。
  3. Jetty を再起動するだけで、欠落しているディレクトリが再作成され、サービスが再び起動します。

Windows で NFS を介して JAR 内のリソースをロードしているときに、一部の人々が同様の問題を報告したことは、私たちが得た良いヒントです (ネットワーク接続が短時間失われると、NFS ハンドルが無効になり、JVM が同様のエラーで失敗します)。これは私たちの場合 (/tmp はローカル ストレージ) ではありませんが、非常によく似ています。

助けてくれてありがとう。

于 2013-09-17T01:11:35.343 に答える
0

スタック トレースは、それが注釈の処理に関するものであり、コードを実行するためのクラスのロードとは関係がないことを示しています。注釈プロセッサは、注釈付き要素のを通じて注釈メンバーの値を解決しようとしているようです。ClassLoader

つまり、次のようなクラス型の値を持つアノテーションと、@Foo(xyz=ABC.class)このコンストラクトでアノテーションが付けられたクラスまたはメンバーがありますが、実行時にアノテーションが付けられた要素をABC介してクラスに到達できません。ClassLoader

これは、このクラスが別の を介してすでにロードされているという事実と矛盾しませんClassLoader

于 2013-09-12T09:16:41.670 に答える