Java 1.6 (1.6.0_02 または 1.6.0_04) を使用する Red Hat Linux (カーネル バージョンは 2.4.21-37.ELsmp) を実行しているテスト マシンで問題が発生しています。問題は、1 つのスレッド グループに特定の数のスレッドが作成されると、オペレーティング システムがそれ以上のスレッドを作成したくない、または作成できないことです。
C のスレッド制限プログラムは約 1.5k のスレッドを作成できたため、これはスレッドを作成する Java に固有のものと思われます。さらに、これは Java 1.4 JVM では発生しません... 1.4k を超えるスレッドを作成できますが、明らかに OS に関して処理が異なります。
この場合、切断されているスレッドの数はわずか 29 スレッドです。これは、エラーが発生するまでスレッドを作成し、作成したスレッドの数を出力する単純な Java プログラムでテストできます。エラーは
java.lang.OutOfMemoryError: 新しいネイティブ スレッドを作成できません
これは、他のプロセスやユーザーが使用しているスレッドの数や、システムがその時点で使用しているメモリの総量などの影響を受けないようです。Xms、Xmx、Xss などの JVM 設定も何も変更しないようです (問題がネイティブ OS スレッドの作成にあるように思われることを考えると、これは予想されることです)。
「ulimit -a」の出力は次のとおりです。
コア ファイル サイズ (ブロック、-c) 0 データ セグメント サイズ (キロバイト、-d) 無制限 ファイルサイズ (ブロック、-f) 無制限 最大ロック メモリ (キロバイト、-l) 4 最大メモリ サイズ (キロバイト、-m) 無制限 ファイルを開く (-n) 1024 パイプ サイズ (512 バイト、-p) 8 スタックサイズ (キロバイト、-s) 10240 CPU 時間 (秒、-t) 無制限 最大ユーザー プロセス (-u) 7168 仮想メモリ (キロバイト、-v) 無制限
ユーザープロセスの制限は問題ではないようです。何が間違っている可能性があるかについての情報を検索してもあまりヒットしませんでしたが、この投稿は、少なくとも一部の Red Hat カーネルがプロセスをスタックに割り当てられるメモリを 300 MB に制限し、スタックのスレッドごとに 10 MB に制限しているようです。問題がそこにある可能性があります(奇妙でありそうもないようですが)。
これをテストするために「ulimit -s」でスタック サイズを変更しようとしましたが、10240 以外の値と JVM は次のエラーで起動しません。
VM の初期化中にエラーが発生しました VM スレッドを作成できません。システム リソースが不足しています。
私は一般的に Linux を回避できますが、システム構成についてはあまり知りません。また、この種の状況に具体的に対処するものを見つけることができませんでした。これを引き起こしている可能性のあるシステムまたは JVM 設定についてのアイデアをいただければ幸いです。
編集: plinthで言及されているスレッド制限プログラムを実行すると、1529 番目のスレッドを作成しようとするまで失敗はありませんでした。
この問題は、1.4 JVM を使用しても発生しませんでした (1.6.0_02 および 1.6.0_04 JVM で発生します。現時点では 1.5 JVM ではテストできません)。
私が使用しているスレッド テストのコードは次のとおりです。
public class ThreadTest {
public static void main(String[] pArgs) throws Exception {
try {
// keep spawning new threads forever
while (true) {
new TestThread().start();
}
}
// when out of memory error is reached, print out the number of
// successful threads spawned and exit
catch ( OutOfMemoryError e ) {
System.out.println(TestThread.CREATE_COUNT);
System.exit(-1);
}
}
static class TestThread extends Thread {
private static int CREATE_COUNT = 0;
public TestThread() {
CREATE_COUNT++;
}
// make the thread wait for eternity after being spawned
public void run() {
try {
sleep(Integer.MAX_VALUE);
}
// even if there is an interruption, dont do anything
catch (InterruptedException e) {
}
}
}
}
これを 1.4 JVM で実行すると、これ以上スレッドを作成できず、kill -9 が必要なときにハングします (少なくとも私にはそうでした)。
もっと編集:
問題が発生しているシステムは LinuxThreads スレッド モデルを使用しているのに対し、正常に動作する別のシステムは NPTL モデルを使用していることが判明しました。