2009-03-18 3 views
43

作業中は、 "PermGen out of memory"の例外を除いて、チームリーダーがJVMのバグであると判断しました。これはコードのホットデプロイに関連しています。多くの詳細を説明することなく、彼はホットな展開は「難しい問題」だと指摘しました。だから、.NETはまだそれをやっていません。ホットデプロイメントを「難しい問題」にする要因は何ですか?

鳥瞰図からのホットデプロイメントを説明する記事が多数見つかりましたが、技術的な詳細は常に不足しています。誰もが私に技術的な説明を教えて、ホット展開が「難しい問題」である理由を説明できますか?

+0

ところで、このコミュニティWikiはなぜですか? – Eddie

+2

私は不明なものを残した場合に役立つと思っていました...デフォルトでは、それは悪い礼儀ですか? –

+0

おかしい:ちょっと今、再読書中にthink-oを見つけた、ありがとう! –

答えて

58

クラスがロードされると、クラスに関するさまざまな静的データがPermGenに格納されます。このClassインスタンスへのライブ参照が存在する限り、クラスインスタンスはガベージコレクションできません。

私はこの問題の一部は、GCが古いクラスインスタンスをperm genから削除するかどうかに関係していると考えています。通常、ホットデプロイするたびに、新しいクラスインスタンスがPermGenメモリプールに追加され、古いものは使用されなくなり、通常は削除されません。デフォルトでは、Sun JVMはPermGenでガベージコレクションを実行しませんが、これはオプションの "java"コマンド引数で有効にすることができます。

したがって、十分な時間をホット展開すると、最終的にPermGenスペースが使い果たされます。

完全にをデプロイしない場合、たとえば、スレッドが実行されていない場合、そのWebアプリケーションで使用されるすべてのクラスインスタンスがPermGenスペースに固定されます。再デプロイし、これらすべてのクラスインスタンスの別のコピーをPermGenにロードします。アンデプロイし、スレッドはPermGenのクラスインスタンスの別のセットを固定します。再配布してネットセット全体をロードしてください。最終的にPermGenがいっぱいになります。 PermGenにし、クラスのGCを有効にするために、最近の日JVMにコマンド引数を供給

  • あなたは時々によってこの問題を解決することができます。つまり:-XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

  • が固定サイズPermGenかを使用しない別のJVMを使用することがロードされたクラス

にGCを行いますが、これはあなたのWebアプリは完全に正常にシャットダウンのみ場合を助けます、そのWebアプリケーションのクラスローダーによってロードされたクラスのいずれかのClassインスタンスへのライブ参照は残されません。

これでも、クラスローダのリークによって問題が解決するとは限りません。 (いくつかのケースではあまりにも多くの中身の文字列と同様に)。

詳細については、次のリンクを参照してください(2つの太字は問題の一部を示す良い図です)。

+1

Eddie - クラスを維持する理由はありません。なぜなら、既存のオブジェクトが「古い」クラス定義でノックしているからです。 –

+0

@Edie:ほとんどのリンクは、ホット・デプロイがなぜ問題であるかを理解するのに最も役立つクラスローダー・アーキテクチャーではなく、メモリーに関連しています。メモリの問題は、回避策の結果です。 – OscarRyz

+0

スレッドを実行しているだけのことを書き留めておきます。誤って再デプロイしたスレッドをスリープ状態にしたときに、スレッドが起動してNoClassDefFound(クラスが展開されなかった)がスローされた後、(もちろん)死後、PermGenはGCされるべきである。 –

6

一般的に問題が実際にいること持つクラスを阻止しようとしたJavaのセキュリティモデルでありますすでにロードされています。

もちろん、Javaは当初から動的クラスローディングをサポートしていましたが、クラス再ロードは難しいです。

実行中のJavaアプリケーションに悪意のあるコードを含む新しいクラスが注入されていることが有害である(と理由がある)と考えられました。たとえば、インターネットからのjava.lang.Stringクラッキングされた実装では、文字列を生成する代わりに、メソッドlength()を呼び出すランダムなファイルが削除されます。

したがって、Javaは考えられました(そして、結果的に.NET CLRと思われます。これは、JVMの "インスピレーション"が高いためです)。すでにロードされているクラスが同じVMを再びロードするのを防ぐためでした。

彼らはこの「機能」を無効にする仕組みを提供しました。クラスローダーは、クラスローダーのルールでも、新しいクラスをロードしようとする前に "親"クラスローダーに許可を求めてください。親クラスが既にクラスをロードしている場合、新しいクラスは無視されます。例えば

私は、アプリケーション・サーバーは、Java EEのための主流になった(ともマイクロコンテナの必要性を作成するときに

はホットデプロイは、Javaの世界で必要となりLDAPやRDBMSからクラスをロードするクラスローダーを使用していましたこの種の負担を避けるために春のように)。

すべてのコンパイル後にアプリケーションサーバー全体を再起動すると誰もが狂ってしまう。

アプリサーバープロバイダは、この「カスタム」クラスローダーを提供してホットデプロイメントを支援し、設定ファイルを使用することで、その動作を本番環境で設定すると無効にするべきです(SHOULD)。しかし、トレードオフは、開発に膨大なメモリを使用しなければならないということです。したがって、これを行う良い方法は、3〜4回の展開ごとに再起動することです。

これは、最初からクラスをロードするように設計された他の言語では発生しません。

たとえば、実行中のクラスにメソッドを追加したり、実行時にメソッドをオーバーライドしたり、固有の特定のオブジェクトに単一のメソッドを追加することさえできます。

これらの種類の環境でのトレードオフはもちろんメモリとスピードです。

こちらがお役に立てば幸いです。私はリロードが可能な限りシンプルにあることを約束するいくつかの時間前にこの製品を見つけた

EDIT。私は最初にこの答えを書いたときにリンクを覚えていませんでした。

これは、Sun JVMが宇宙固定PermGenたJavaRebel from ZeroTurnaround

+0

あなたの頭の中で何が混乱していますか? Javaは実行時にクラスをロードするようには設計されていませんでしたか?そのため、最初からClass.forName()があるのはなぜですか? –

+0

それはオスカーがウラジミールを書いたものではありません。彼は、Javaは実行時にクラスを置き換えるように設計されていないと書いています。 –

+0

ClassLoaderクラスはバージョン1からあります。実行時にクラスを置き換えるようには設計されていませんか?また、セキュリティはPermGen OOMとは関係ありません。 PermGenの制限は、Sun JVMの詳細な実装の詳細です。 –

3

あり、そして最終的には=> OOM(はい、明らかに起因するクラスローダー関連のコードのバグのため)、すべてが消費さです。

他のベンダーのJVM(Weblogicなど)を使用できる場合は、PermGenスペースが動的に拡張されるため、permgen関連のOOMを取得することはありません。

+0

そこに待ってください。これは100%真実ではありません。パーマネント・ジェムの問題は、JVMとそのライブラリに関連するだけでなく、アプリケーションが正しくないと、PermGenエラーが発生することもあります。また、PerGenを動的に拡張することは、それを解決することとは全く異なっています。任意のVMで十分な時間待って、問題が発生します。 – Antonio

+1

修正します。それでも、動的なPermGenを使用すると、より多くのホットな展開に耐えることができます。 Sun JVMでは、再デプロイメント#1で頻繁に発生します。-E –

0

ご使用のJavaのバージョンは?サン1.4.2の初期にはバグがありましたが、長い間、長い間働いていました。
ところで、あなたはチームのリーダーにどのようにニュースを伝えますか?あなたはチームリードですか?

+0

1.5以降、実際には新しい問題です。あるいは、少なくとも私は1.5でそれに遭遇しました。 –

+0

私たちは1.6でこの問題に取り組んでいます。 私はおそらくこのページへのリンクを送ることによって私のチームリードに「これを壊すでしょう。 –

関連する問題