java.lang.OutOfMemoryErrorの原因:新しいネイティブスレッドを作成できません
1. 序章
このチュートリアルでは、 java .lang.OutOfMemoryError:新しいネイティブスレッドエラーを作成できない原因と考えられる解決策について説明します。
2. 問題を理解する
2.1. 問題の原因
ほとんどのJavaアプリケーションは本質的にマルチスレッドであり、複数のコンポーネントで構成され、特定のタスクを実行し、異なるスレッドで実行されます。 ただし、基盤となるオペレーティングシステム(OS)は、Javaアプリケーションが作成できるスレッドの最大数に上限を課しています。
- Java仮想マシン(JVM)内で実行されているアプリケーションが、新しいスレッドを要求します
- JVMネイティブコードは、新しいカーネルスレッドを作成するための要求をOSに送信します
- OSは、メモリ割り当てを必要とする新しいカーネルスレッドを作成しようとします
- OSは、次のいずれかの理由でネイティブメモリの割り当てを拒否します
- 要求しているJavaプロセスがメモリアドレス空間を使い果たしました
- OSが仮想メモリを使い果たしました
- 次に、Javaプロセスは java.lang.OutOfMemoryErrorを返します:新しいネイティブスレッドを作成できませんエラー
2.2. スレッド割り当てモデル
OSには通常、 2種類のスレッドがあります。ユーザースレッド(Javaアプリケーションによって作成されたスレッド)とカーネルスレッドです。 ユーザースレッドはカーネルスレッドの上でサポートされ、カーネルスレッドはOSによって管理されます。
それらの間には、3つの一般的な関係があります。
- 多対1–多くのユーザースレッドが単一のカーネルスレッドにマップされます
- 1対1–1つのユーザースレッドを1つのカーネルスレッドにマップ
- 多対多–多くのユーザースレッドが少数または同数のカーネルスレッドに多重化されます
3. エラーの再現
連続ループでスレッドを作成し、スレッドを待機させることで、この問題を簡単に再現できます。
while (true) {
new Thread(() -> {
try {
TimeUnit.HOURS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
各スレッドを1時間保持しているため、新しいスレッドを継続的に作成しながら、OSからのスレッドの最大数にすばやく到達します。
4. ソリューション
このエラーに対処する1つの方法は、OSレベルでスレッド制限の構成を増やすことです。
ただし、 OutOfMemoryError はプログラミングエラーを示している可能性があるため、これは理想的なソリューションではありません。 この問題を解決する他のいくつかの方法を見てみましょう。
4.1. エグゼキュータサービスフレームワークの活用
Javaのエグゼキュータサービスフレームワークをスレッド管理に活用することで、この問題にある程度対処できます。 デフォルトのエグゼキュータサービスフレームワーク、またはカスタムエグゼキュータ設定は、スレッドの作成を制御できます。
Executors#newFixedThreadPool メソッドを使用して、一度に使用できるスレッドの最大数を設定できます。
ExecutorService executorService = Executors.newFixedThreadPool(5);
Runnable runnableTask = () -> {
try {
TimeUnit.HOURS.sleep(1);
} catch (InterruptedException e) {
// Handle Exception
}
};
IntStream.rangeClosed(1, 10)
.forEach(i -> executorService.submit(runnableTask));
assertThat(((ThreadPoolExecutor) executorService).getQueue().size(), is(equalTo(5)));
上記の例では、最初に5つのスレッドと実行可能なタスクを含む固定スレッドプールを作成し、スレッドを1時間待機させます。 次に、そのような10個のタスクをスレッドプールに送信し、5個のタスクがエグゼキュータサービスキューで待機していることを表明します。
スレッドプールには5つのスレッドがあるため、いつでも最大5つのタスクを処理できます。
4.2. スレッドダンプのキャプチャと分析
スレッドダンプのキャプチャと分析は、スレッドのステータスを理解するのに役立ちます。
サンプルのスレッドダンプを見て、何を学ぶことができるか見てみましょう。
上記のスレッドスナップショットは、前に示した例のJavaVisualVMからのものです。 このスナップショットは、継続的なスレッドの作成を明確に示しています。
継続的なスレッドの作成があることを確認したら、アプリケーションのスレッドダンプをキャプチャして、スレッドを作成しているソースコードを特定できます。
上記のスナップショットでは、スレッドの作成に関与するコードを特定できます。 これは、適切な対策を講じるための有用な洞察を提供します。
5. 結論
この記事では、 java .lang.OutOfMemoryError:新しいネイティブスレッドエラーを作成できませんでした。これは、Javaでの過度のスレッド作成が原因であることがわかりました。 ] 応用。
この問題に取り組むための2つの有用な手段として、 ExecutorService フレームワークとスレッドダンプ分析を検討することにより、エラーに対処して分析するためのいくつかのソリューションを検討しました。
いつものように、記事のソースコードはGitHubでから入手できます。