我在使用 Java 1.6(1.6.0_02 或 1.6.0_04)运行 Red Hat Linux(内核版本为 2.4.21-37.ELsmp)的测试机器上遇到问题。问题是,一旦在单个线程组中创建了一定数量的线程,操作系统就不愿意或无法再创建。
这似乎特定于 Java 创建线程,因为 C 线程限制程序能够创建大约 1.5k 线程。此外,Java 1.4 JVM 不会发生这种情况......它可以创建超过 1.4k 个线程,尽管它们显然在操作系统方面的处理方式不同。
在这种情况下,它切断的线程数仅为 29 个线程。这可以通过一个简单的 Java 程序进行测试,该程序只创建线程,直到出现错误,然后打印它创建的线程数。错误是一个
java.lang.OutOfMemoryError:无法创建新的本地线程
这似乎不受其他进程或用户使用的线程数或系统当时使用的内存总量等因素的影响。Xms、Xmx 和 Xss 等 JVM 设置似乎也没有改变任何东西(这是意料之中的,考虑到问题似乎与本机 OS 线程创建有关)。
“ulimit -a”的输出如下:
核心文件大小(块,-c)0 数据段大小 (kbytes, -d) 无限制 文件大小(块,-f)无限制 最大锁定内存 (kbytes, -l) 4 最大内存大小 (kbytes, -m) 无限制 打开文件 (-n) 1024 管道大小(512 字节,-p)8 堆栈大小(千字节,-s)10240 cpu时间(秒,-t)无限制 最大用户进程 (-u) 7168 虚拟内存 (kbytes, -v) 无限制
用户进程限制似乎不是问题。搜索可能出错的信息并没有太多,但这篇文章似乎表明,至少有一些 Red Hat 内核将进程限制为为堆栈分配 300 MB 内存,并且每个线程为堆栈分配 10 MB 内存,似乎就像问题可能存在一样(尽管它似乎也很奇怪且不太可能)。
我尝试使用“ulimit -s”更改堆栈大小来测试这一点,但除 10240 和 JVM 之外的任何值都不会以以下错误开始:
初始化虚拟机时出错 无法创建 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 模型。