(20)私はちょうどインタビューを受けて、Javaでメモリリークを作成するように求められました。言うまでもなく、私はそれを作成し始める方法についての手がかりがないかわいそうだと感じました。例は何でしょうか?sun.misc.Unsafeクラスでメモリリークを起こすことができます。java.nioクラス)で使用されます。インスタンスを作成することができます。e.printStacktrace();}JVMのガベージコレクタから到達できない領域(ネイティブメソッドによって割り当てられたメモリなど)Webアプリケーションでは、一部のオブジェクトは、アプリケーションが明示的に停止または削除されるまで、アプリケーションスコープに格納されます。jdk設定を参照してください。その参照は、巨大なオブジェクトを生きているかもしれない...ここの例のほとんどは「複雑すぎる」です。彼らはエッジケースです。JAVA(静的なクラスの読み込み...)のコーナーケースに噛まれました。インタビュアーが望んでいるタイプのものではなく、最も一般的なケースでもないと思います。実際にはメモリリークの場合があります。ガベージコレクタは、もはや参照されていないものだけを解放します。Java開発者はメモリを気にしません。私たちは必要に応じてそれを割り当て、自動的に解放させます。長期間使用されるアプリケーションでは、状態が共有される傾向があります。それは何でも、静的であっても、シングルトンであってもかまいません。通常、アプリケーションは複雑なオブジェクトグラフを作成する傾向があります。nullへの参照を設定することを忘れたり、コレクションから1つのオブジェクトを削除することを頻繁に忘れると、メモリリークを起こすだけで十分です。UIリスナーのようなあらゆる種類のリスナー、キャッシュ、または長命の共有状態では、適切に処理されないとメモリリークが発生する傾向があります。これはJavaのコーナーケースではなく、ガベージコレクタの問題ではないことが理解されます。それは設計上の問題です。長寿命オブジェクトにリスナーを追加するように設計しましたが、不要になったリスナーは削除しません。オブジェクトはキャッシュされますが、キャッシュから削除する方法はありません。我々は、計算によって必要とされる以前の状態を記憶する複雑なグラフを有している可能性がある。以前の状態はそれ自体が前の状態にリンクされています。私たちはSQL接続やファイルを閉じる必要があります。nullへの適切な参照を設定し、コレクションから要素を削除する必要があります。適切なキャッシング戦略(最大メモリサイズ、要素数、またはタイマー)が必要です。リスナーに通知を許可するすべてのオブジェクトは、addListenerメソッドとremoveListenerメソッドの両方を提供する必要があります。これらの通知が使用されなくなったら、リスナーリストをクリアする必要があります。メモリリークは確かに本当に可能であり、完全に予測可能です。特別な言語機能やコーナーケースは必要ありません。メモリリークは、何か不足している可能性があるか、または設計上の問題があるかのいずれかの指標です。メモリリークとは何ですか?これはバグやデザインの悪さによるものです。それは記憶の浪費です。時間が経つと悪化します。ガーベッジコレクターはそれをきれいにすることはできません。典型的な例:オブジェクトのキャッシュは、物事を混乱させる良い出発点です。info;}キャッシュが成長し、成長します。データベース全体がメモリに吸い込まれます。良いデザインは、LRUMap(最近使用されたオブジェクトのみをキャッシュに保持する)を使用します。確かに、あなたは事をもっと複雑にすることができます:ThreadLocal構造を使用します。複雑な参照ツリーを追加する。サードパーティのライブラリによって引き起こされたリーク。何が起こるか:このInfoオブジェクトに他のオブジェクトへの参照が含まれている場合、そのオブジェクトは他のオブジェクトへの参照を持ちます。ある意味では、これはある種のメモリリークであるとも考えられます(悪いデザインによるもの)。不要になったオブジェクトを参照する場合はいつでも、メモリリークが発生します。Javaでメモリリークがどのように現れ、どのようにできるかについては、Javaプログラムでのメモリリークの処理を参照してください。JDBC理解していない場合、非常に意味のない例です。StatementおよびResultSetインスタンスを破棄したり、それらへの参照を失う前に閉じることを期待finalizeます。Connectionオブジェクトが閉じられていないため、ガベージコレクタが周囲に来て到達不能になるまで物理接続が開いたままであることです。finalize実装しないJDBCドライバがあります。Connectionオブジェクトに関連付けられたリソース(メモリを含む)は単に再利用されない可能性があります。Connectionのfinalizeメソッドがすべてをクリーンアップしないようなイベントでは、実際にデータベースサーバーへの物理的接続がいくつかのガベージコレクションサイクルを継続することがあります。)、閉じなければならない。JDBCドライバがfinalizeを実装finalize場合でも、ファイナライズ時に例外がスローされる可能性があります。"休止中の"オブジェクトに関連付けられたメモリは再利用されません。オブジェクトの終了時に例外が発生する上記のシナリオは、メモリリーク、オブジェクトの復活につながる可能性のある別のシナリオに関連しています。オブジェクトの復活は、他のオブジェクトから、オブジェクトのファイナライズが行われないように強い参照を作成することによって、意図的に行われることがよくあります。オブジェクトの復活を悪用すると、他のメモリリークの原因と組み合わせてメモリリークが発生します。あなたが上手く描くことができる多くの例がありますリストに追加するだけでリストから削除しない場合のListインスタンスの管理(不要になった要素を削除する必要があります)、またはSocketまたはFileオープンしFileが、もはやそれらが必要でなくなったときにクローズしません(上記のConnectionクラスに関連する例に似ています)。EEアプリケーションを停止するときにシングルトンをアンロードしない。シングルトンクラスをロードしたClassloaderはクラスへの参照を保持するため、シングルトンインスタンスは決して収集されません。アプリケーションの新しいインスタンスがデプロイされると、通常は新しいクラスローダが作成され、以前のクラスローダはシングルトンのために存在し続けます。私は、有効な例として、スレッドがプールされている環境でThreadLocal変数を使用することができると思います。サーブレットでThreadLocal変数を使用して他のWebコンポーネントと通信し、そのスレッドがコンテナによって作成され、アイドル状態のものをプール内に維持することができます。ThreadLocal変数は、正しくクリーンアップされていないと、同じWebコンポーネントがそれらの値を上書きするまで、そこに存続します。特定されると、問題は簡単に解決できます。私は最近、log4jによるメモリリークの状況に遭遇しました。Context)と呼ばれるこのメカニズムを備えています。NDCが動作する粒度はスレッドなので、別々のスレッドからログ出力を区別します。スレッド固有のタグを格納するために、log4jのNDCクラスは、Threadオブジェクト自体によって(スレッドIDとは対照的に)キー入力されるHashtableを使用します。したがって、NDCタグがスレッド内に存在するすべてのオブジェクトオブジェクトもメモリに留まります。Webアプリケーションでは、NDCを使用してログIDを指定してログ出力にタグ付けし、ログを単一のリクエストと区別します。NDCタグをスレッドに関連付けるコンテナは、要求からの応答を返す間にNDCタグも削除します。この問題は、リクエストの処理中に子スレッドが生成されたときに発生しました。次のようなコードです。したがって、NDCコンテキストは、生成されたインラインスレッドに関連付けられていました。このNDCコンテキストのキーとなったスレッドオブジェクトは、hugeListオブジェクトがハングしているインラインスレッドです。したがって、スレッドがやっていることを終えた後でさえ、hugeListへの参照はNDCコンテキストHastableによって生き残り、メモリリークを引き起こしていました。答えは、インタビュアーが何を求めていると思ったかによってまったく異なります。他の答えにはたくさんの例があります。質問されているかもしれない複数のメタ質問がありますか?理論的に「完璧な」Java実装はリークに対して脆弱ですか?候補者は理論と現実の違いを理解していますか?候補者はガベージコレクションの仕組みを理解していますか?またはガベージコレクションが理想的なケースでどのように動作するはずですか?ネイティブインターフェイスを通じて他の言語を呼び出せることは知っていますか?彼らは他の言語で記憶を漏らすことを知っていますか?候補者はメモリ管理が何であるか、そしてJavaの場面で何が起こっているのかを知っていますか?私はあなたのメタ質問を「私はこのインタビュー状況で使用した答えは何ですか?」と読んでいます。したがって、私はJavaの代わりにインタビュー技術に焦点を当てます。インタビューで質問に対する答えを知らないという状況を繰り返す可能性が高いと思うのは、あなたがJavaのリークをどうやって作るのかを知る必要がある場所にいるはずです。うまくいけば、これは助けになるでしょう。インタビューのために開発できる最も重要なスキルの1つは、積極的に質問に耳を傾け、インタビュアーと協力してその意図を抽出することです。これにより、あなたは彼らが望むように質問に答えるだけでなく、あなたにいくつかの重要なコミュニケーションスキルがあることが示されます。同様に多くの才能のある開発者の間の選択肢になると、毎回対応する前に聞き、考え、理解する人を雇うつもりです。純粋なJavaで真のメモリリーク(コードを実行してもアクセスできないがメモリに格納されていないオブジェクト)を作成するには、以下のようにしてください。アプリケーションは、実行時間の長いスレッドを作成します(またはスレッドプールを使用してさらに速くリークします)。スレッドは、(オプションとしてカスタムの)ClassLoaderを介してクラスをロードします。)を割り当て、静的なフィールドにそれを格納し、自身への参照をThreadLocalに格納します。余分なメモリを割り当てることはオプションです(Classインスタンスが漏れていれば十分ですが)、リーク作業がずっと速くなります。スレッドは、ロードされたカスタムクラスまたはClassLoaderへのすべての参照をクリアします。これは、ThreadLocalがオブジェクトへの参照を保持するため、ClassLoaderへの参照を保持するClassへの参照を保持するためです。ClassLoaderは、ロードされたすべてのクラスへの参照を保持します。7より前の方が悪かったですが、JVMがクラスのアンロードを処理する方法に関係なく、クラスオブジェクトが再生されることはありません。)このパターンのバリエーションは、何らかの方法でThreadLocalsを使用するアプリケーションを頻繁に再デプロイすると、アプリケーションコンテナ(Tomcatなど)がふるいのようにメモリをリークできる理由です。(アプリケーションコンテナは前述のようにスレッドを使用するため、アプリケーションを再デプロイするたびに新しいClassLoaderが使用されます)。この動作を実際に示すいくつかのコード例を示します。http://wiki.eclipse.org/Performance_Bloopers#String.substring.28.29シンプルで邪悪なものがありhttp://wiki.eclipse.org/Performance_Bloopers#String.substring.28.29。}}部分文字列は元の文字列、つまりはるかに長い文字列の内部表現を参照するため、元の文字はメモリに残ります。したがって、StringLeakerを演奏している限り、文字列を保持していると思うかもしれませんが、メモリ内に元の文字列全体があります。元の文字列への不要な参照を格納しないようにするには、次のようにします。1).intern();...そうすることで、StringLeakerインスタンスが破棄された後であっても、オリジナルの長い文字列と導出された部分文字列がメモリに保持されます。そのクラスのfinalizeメソッドでクラスの新しいインスタンスを作成することによって、メモリリークを作成することができます。ファイナライザが複数のインスタンスを作成した場合のボーナスポイント。}}インタビュアーはおそらく以下のコードのような循環参考文献を探していたでしょう(参照計数を使用していた非常に古いJVMのメモリーが漏れているだけです)。それは非常にあいまいな質問なので、JVMのメモリ管理についてのあなたの理解を誇示することができます。*/}次に、参照カウントで、上記のコードがメモリをリークすることを説明することができます。現代のJVMのほとんどは参照カウントを使用しません。ほとんどの場合、このガベージコレクタを使用します。これは実際にこのメモリを収集します。次に、基本的なネイティブリソースを持つObjectの作成について説明します。}}次に、これは技術的にメモリリークだと説明できますが、実際には、Javaコードによって解放されなかったネイティブリソースをJVM内のネイティブコードによって割り当てられているネイティブコードが原因です。今日の終わりには、現代のJVMで、JVMの認識の通常の範囲外でネイティブリソースを割り当てるJavaコードを記述する必要があります。メモリに漏れるさまざまな状況があります。露出してはならない地図を他の場所で公開しています。{}任意のサーブレットコンテナ(Tomcat、Jetty、Glassfishな​​ど)で実行されているWebアプリケーションを取り出します。アプリを10または20回続けて再デプロイします(サーバーのautodeployディレクトリにあるWARに触れるだけで十分です)。誰かが実際にこれをテストしていない限り、いくつかの再デプロイ後にOutOfMemoryErrorが発生する可能性が高いです。アプリケーションはそれ以降にクリーンアップを気にかけないからです。あなたは、このテストであなたのサーバにバグを見つけることさえできます。問題は、コンテナの存続期間がアプリケーションの存続期間よりも長いことです。コンテナーがアプリケーションのオブジェクトやクラスに持つすべての参照をガベージコレクションできることを確認する必要があります。あなたのWebアプリケーションの展開解除から生き残った参照が1つしかない場合、対応するクラスローダと結果としてあなたのWebアプリケーションのすべてのクラスはガベージコレクションできません。アプリケーションによって起動されるスレッド、ThreadLocal変数、ロギングアペンダは、クラスローダのリークを引き起こす通常の疑いのあるものです。"メモリリーク"を経験しました。私たちが使ったXMLパーサ(どれがどちらか覚えていない)は、比較を高速化するために、タグ名にString.intern()を付けました。私たちの顧客の一人は、XML属性やテキストではなく、タグ名としてデータ値を格納するという素晴らしいアイデアを持っていました。...</data>実際には、数字は使用せず、1日に10~1500万の割合で入ってきた独自のテキストID(約20文字)を使用しました。MBのゴミが発生します。これは決して再び必要とされません。GCedは決してパーマネントではありません。MBに設定されていたので、メモリ不足例外(OOME)が到着するまでに約2日間かかりました...私は最近、より微妙な種類のリソースリークに遭遇しました。クラスローダーのgetResourceAsStreamを介してリソースを開き、入力ストリームハンドルが閉じられていないことが起こりました。うーん、あなたは、馬鹿なことを言うかもしれない。JVMのヒープではなく、元のプロセスのヒープメモリがリークする可能性があります。Javaコードから参照されるファイルが入ったjarファイルだけが必要です。jarファイルが大きければ大きいほど、より速いメモリが割り当てられます。このようなjarファイルは、次のクラスで簡単に作成できます。BigJarCreatorEtvoilà:現在の作業ディレクトリに2つのファイルが入ったjarアーカイブがあります。}}このクラスは基本的に何もしませんが、参照されていないInputStreamオブジェクトを作成します。これらのオブジェクトはすぐにガベージコレクトされるため、ヒープサイズには寄与しません。この例では、jarファイルから既存のリソースをロードすることが重要です。サイズはここで重要です。疑わしい場合は、上記のクラスをコンパイルして開始してください。MB)を選択してください。MemLeak参照が保持されていないため、ここでOOMエラーが発生することはありません。上記の例では、ITERATIONSをどれだけ大きく選択しても、アプリケーションは動作し続けます。RSS)またはプロセスエクスプローラで表示)は増加します。MBのメモリを割り当てます。アプリケーションを安全に再生したい場合は、作成された入力ストリームを閉じます。単純で驚くべきことです。誰もが常にネイティブコードルートを忘れてしまいます。リークの簡単な公式は次のとおりです。ネイティブメソッドを宣言します。ネイティブメソッドでは、呼び出しますmalloc。電話しないでくださいfree。ネイティブメソッドを呼び出します。ネイティブコードのメモリ割り当ては、JVMヒープからのものであることに注意してください。誰も内部クラスの例を使用していないのは面白いと思った。あなたが内部クラスを持っている場合。本質的にそれを含むクラスへの参照を維持します。Javaは最終的にはそれをきれいにするので、技術的にはメモリリークではありません。これにより、クラスが予期されていたよりも長くぶら下がる可能性があります。}}今度はExample1を呼び出し、Example2をExample1を破棄すると、本質的にExample1オブジェクトへのリンクが残っています。}}私はまた、特定の時間よりも長く存在する変数を持っていれば噂が聞こえました。Javaはそれが常に存在すると想定し、コード内でこれ以上到達できない場合、実際にはそれをクリーンアップしようとはしません。それは完全に未確認です。memory-leaksJavaは「参照渡し」または「渡し渡し」ですか?配列からArrayListを作成するJavaのデストラクタはありますか?public、protected、package-private、privateのJavaの違いは何ですか?メモリリークはこれまでOKですか?どのようにJavaで特定の範囲内のランダムな整数を生成するには?どのようにJavaの文字列値から列挙型の値を取得するには?最初に追加されたアクティビティがリークしましたJavaで文字列をintに変換するにはどうすればよいですか?performSelectorはセレクタが不明なためにリークする可能性があります日本語Top。