Java.Lang.OutOfMemoryError: 新しいネイティブ スレッドを作成できません
この記事では、Java の java.lang.OutOfMemoryError: 新しいネイティブ スレッドを作成できません
エラーについて学習します。
Java で新しいネイティブ スレッド エラーを作成できない
Java で構築された実際のアプリケーションのほとんどは、本質的にマルチスレッドであり、さまざまなタスクを実行する多くのコンポーネントがあります。 これらのタスクは、スループットを向上させるために異なるスレッドで実行されます。 ただし、Java アプリケーションが作成できるスレッドの最大数は、使用しているオペレーティング システム (OS) によって異なります。
そのため、オペレーティング システムが新しいカーネル スレッド (システム スレッドまたは OS スレッドとも呼ばれる) を作成できない場合は常に、Java 仮想マシン (JVM) によって新しいネイティブ スレッドを作成できません
というエラーがスローされます。
バックエンドで次のイベントが発生し、このエラーが発生します。
- JVM 内のプログラム/アプリケーションがオペレーティング システムに新しいスレッドを要求します。
- JVM ネイティブ コードによって新しいカーネル スレッドを作成する要求が OS に送信されます。
- オペレーティング システムは、メモリ割り当て手順を含む新しいスレッドを作成しようとします。
- 仮想メモリが OS によって使い果たされているか、要求元の Java アプリケーションによってメモリ アドレス空間が使い果たされているため、オペレーティング システムはメモリを割り当てることができません。
- JVM が
新しいネイティブ スレッドを作成できません
というエラーをスローします。
それをよりよく理解するために例を見てみましょう。
import java.util.concurrent.TimeUnit;
public class Test {
public static void main(String[] args) {
while (true) {
new Thread(() -> {
try {
TimeUnit.HOURS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
}
上のコードでは、無限ループを利用してスレッドを作り続けて待機させていますが、1時間スレッドを保持したまま作り続けているため、OSが許容する最大スレッド数にすぐに達してしまいます。
java.lang.OutOfMemoryError: 新しいネイティブ スレッドを作成できません
を解決する方法
では、このエラーを解決するにはどうすればよいですか、または回避策はありますか?
1つの解決策は、OS レベルで設定を変更して許可されるスレッドの数を増やすことですが、この解決策は 2つの理由で実行できません。
- まず、OS レベルでの再構成は容易ではなく、推奨されません。
- 2 番目に、ほとんどの場合、OS スレッドの制限とは関係ありません。 プログラミングエラーがあるためにエラーが発生します。 たとえば、上記のプログラムでは、理想的な方法ではない無限ループを使用して連続的に作成しています。
別の解決策または回避策は、ExecutorService
フレームワークを使用して、特定の時間に処理できるスレッド プール内のスレッド数を制限することです。
例:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
public class Test {
public static void main(String[] args) {
ExecutorService es = Executors.newFixedThreadPool(10);
Runnable tasks = () -> {
try {
TimeUnit.HOURS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
};
IntStream.rangeClosed(1, 15).forEach(x -> es.submit(tasks));
}
}
コードでは、最大 10 個のスレッドを持つことができる固定サイズのスレッド プールを作成し、スレッドを 1 時間待機させる Runnable
タスクを作成しました。
IntStream
を使用して、15 個のタスクをスレッド プールに送信したため、10 個が送信され、残りの 5 個は ExecutorService
キューに置かれます。
まとめ
この記事では、Java で新しいネイティブ スレッドを作成できません
というエラーが発生するのは、オペレーティング システムが新しいカーネル スレッドを作成できない場合であることを学びました。 また、ExecutorService
フレームワークを使用したソリューションまたは回避策も検討しました。