先ほど面接があり、Java でメモリ リークを作成するように求められました。
言うまでもなく、どうやって作り始めればいいのか全くわからず、とてもバカな気分になりました。
例は何でしょうか?
ベストアンサー1
純粋な Java で真のメモリ リーク (実行中のコードではアクセスできないが、メモリ内にまだ保存されているオブジェクト) を作成するための良い方法を次に示します。
- アプリケーションは長時間実行されるスレッドを作成します (または、スレッド プールを使用してさらに高速にリークします)。
- スレッドは (オプションでカスタム) を介してクラスをロードします
ClassLoader
。 - クラスは大量のメモリ (例
new byte[1000000]
) を割り当て、そのメモリへの強い参照を静的フィールドに格納し、次に自分自身への参照を に格納しますThreadLocal
。追加のメモリを割り当てるかどうかはオプションですが (クラス インスタンスをリークするだけで十分)、割り当てるとリークの処理がそれだけ高速化されます。 - アプリケーションは、カスタム クラスまたはその
ClassLoader
ロード元へのすべての参照をクリアします。 - 繰り返す。
Oracle の JDK での実装方法によりThreadLocal
、メモリ リークが発生します。
- それぞれに
Thread
プライベート フィールドがありthreadLocals
、実際にスレッド ローカルの値が格納されます。 - このマップ内の各キーはオブジェクトへの弱参照である
ThreadLocal
ため、そのThreadLocal
オブジェクトがガベージコレクションされた後、そのエントリはマップから削除されます。 - ただし、各値は強い参照であるため、値が (直接的または間接的に)
ThreadLocal
そのキーであるオブジェクトを指している場合、スレッドが存続する限り、そのオブジェクトはガベージ コレクションされることも、マップから削除されることもありません。
この例では、強い参照のチェーンは次のようになります。
Thread
オブジェクト →threadLocals
マップ → サンプル クラスのインスタンス → サンプル クラス → 静的ThreadLocal
フィールド →ThreadLocal
オブジェクト。
( はClassLoader
実際にはリークの作成には関与していませんが、追加の参照チェーン (例のクラス → ClassLoader
→ ロードされたすべてのクラス) によってリークが悪化するだけです。多くの JVM 実装では、特に Java 7 より前のバージョンでは、クラスとClassLoader
が permgen に直接割り当てられ、ガベージ コレクションがまったく行われなかったため、状況はさらに悪化していました。)
このパターンのバリエーションは、何らかの方法で自分自身を指す を使用するアプリケーションを頻繁に再デプロイすると、アプリケーション コンテナー (Tomcat など) がメモリを大量にリークする可能性がある理由ですThreadLocal
。これは、いくつかの微妙な理由で発生する可能性があり、デバッグや修正が困難な場合がよくあります。
更新:多くの人がそれを要求し続けているから、この動作を実際に示すサンプルコードを以下に示します。。