職場では、 " PermGen out of memory "例外で問題が発生しており、チームリーダーは、JVMのバグであると判断しました。これはコードのホットデプロイメントに関連するものです。多くの詳細を説明することなく、彼は、ホットデプロイメントは「難しい問題」であり、.NETでさえまだそれを行っていないほど難しいと指摘しました。
鳥瞰図からホットデプロイメントを説明する記事をたくさん見つけましたが、常に技術的な詳細が不足しています。誰かが私に技術的な説明を指摘し、ホットデプロイメントが「難しい問題」である理由を説明できますか?
クラスがロードされると、クラスに関するさまざまな静的データがPermGenに保存されます。このクラスインスタンスへのライブ参照が存在する限り、クラスインスタンスをガベージコレクションすることはできません。
問題の一部は、GCがpermgenから古いクラスインスタンスを削除する必要があるかどうかに関係していると思います。通常、ホットデプロイするたびに、新しいクラスインスタンスがPermGenメモリプールに追加され、現在は使用されていない古いクラスインスタンスは通常削除されません。デフォルトでは、Sun JVMはPermGenでガベージコレクションを実行しませんが、これはオプションの「Java」コマンド引数で有効にできます。
したがって、十分な回数のホットデプロイを行うと、最終的にPermGenスペースが使い果たされます。
Webアプリがシャットダウンしない場合完全にアンデプロイ時に-たとえば、スレッドが実行されたままの場合-そのWebアプリで使用されるすべてのClassインスタンスがPermGenスペースに固定されます。再デプロイすると、これらすべてのクラスインスタンスの別のコピー全体がPermGenにロードされます。アンデプロイすると、スレッドは続行し、PermGenにクラスインスタンスの別のセットを固定します。コピーのネットセット全体を再デプロイしてロードすると、最終的にPermGenがいっぱいになります。
これは、次の方法で修正できる場合があります。
-XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled
ただし、これは、Webアプリが完全かつクリーンにシャットダウンし、そのWebアプリのクラスローダーによってロードされたクラスのクラスインスタンスへのライブ参照が残っていない場合に役立ちますのみ。
これでも、クラスローダーのリークが原因で、必ずしも問題が解決するとは限りません。 (場合によっては、インターンされた文字列が多すぎます。)
詳細については、次のリンクを確認してください(2つの太字のリンクには、問題の一部を説明するための優れた図があります)。
一般的な問題は、Javaのセキュリティモデルであり、すでにロードされているクラスが再度ロードされるのを実際に防止しようとします。
もちろんJava最初は動的なクラスのロードをサポートしていたので、難しいのはクラスの再ロードです。
実行中のJavaアプリケーションに悪意のあるコードを含む新しいクラスが注入されたのは有害であると考えられていました(そして正当な理由があります)。たとえば、Java.lang.Stringは、インターネットからの実装をクラックしました。文字列を作成する代わりに、メソッドlength()を呼び出すランダムなファイルを削除します。
したがって、彼らはJavaが考案されました(そして、JVMで非常に「インスピレーションを受けた」ため、結果として.NET CLRを推測します)、すでにロードされたクラスが同じVMを再度ロードするのを防ぐことでした。
彼らは、この「機能」を無効にするメカニズムを提供しました。クラスローダーですが、クラスローダーのルールは、新しいクラスをロードする前に「親」クラスローダーに許可を求める必要があります。親がすでにクラスをロードしている場合、新しいクラスは無視されます。
たとえば、LDAPまたはRDBMSからクラスをロードするクラスローダーを使用しました
アプリケーションサーバーがJava EE)の主流になったとき、ホットデプロイはJavaの世界で必要になります(また、回避するためにSpringのようなマイクロコンテナの必要性を生み出します)この種の負担)。
コンパイルのたびにアプリサーバー全体を再起動すると、誰もが夢中になります。
したがって、アプリサーバープロバイダーは、この「カスタム」クラスローダーを提供してホットデプロイメントを支援し、構成ファイルを使用して、その動作を本番環境に設定するときに無効にする必要があります。ただし、トレードオフとして、開発で大量のメモリを使用する必要があります。したがって、これを行う良い方法は、3〜4回の展開ごとに再起動することです。
これは、クラスをロードするために最初から設計された他の言語では発生しません。
たとえば、Ruby)では、実行中のクラスにメソッドを追加したり、実行時にメソッドをオーバーライドしたり、一意の特定のオブジェクトに単一のメソッドを追加したりすることもできます。
これらの種類の環境でのトレードオフは、もちろんメモリと速度です。
これがお役に立てば幸いです。
[〜#〜]編集[〜#〜]
リロードが可能な限り簡単になることを約束するこの製品を少し前に見つけました。この答えを最初に書いたとき、私はリンクを覚えていませんでした、そして私は覚えています。
Sun JVMではPermGenスペースが修正され、最終的にはすべて消費されます(はい、明らかにクラスローダー関連のコードのバグが原因です)=> OOM。
別のベンダーのJVM(Weblogicなど)を使用できる場合は、PermGenスペースが動的に拡張されるため、permgen関連のOOMを取得することはありません。
どのバージョンのJavaを使用していますか?Sun 1.4.2の初期にバグがありましたが、長い間機能していました。
ところで、チームリーダーにニュースをどのように伝えますか?あなたはチームリーダーですか?