我在使用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: unable to create new native thread
这似乎不受其他进程或用户使用的线程数或系统当时使用的内存总量等因素的影响。像Xms,Xmx和Xss这样的JVM设置似乎也没有改变任何东西(考虑到问题似乎与本机OS线程创建有关,这是预期的。)
“ulimit -a”的输出如下:
core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited file size (blocks, -f) unlimited max locked memory (kbytes, -l) 4 max memory size (kbytes, -m) unlimited open files (-n) 1024 pipe size (512 bytes, -p) 8 stack size (kbytes, -s) 10240 cpu time (seconds, -t) unlimited max user processes (-u) 7168 virtual memory (kbytes, -v) unlimited
用户进程限制似乎不是问题。搜索可能出错的信息并没有太多,但this post似乎表明至少有一些Red Hat内核将进程限制为为堆栈分配的300 MB内存,并且每个线程10 MB用于堆栈似乎问题可能存在(虽然看起来很奇怪,也不太可能)。
我尝试使用“ulimit -s”更改堆栈大小来测试它,但除了10240和JVM之外的任何值都不会以错误启动:
Error occurred during initialization of VM Cannot create VM thread. Out of system resources.
我通常可以绕过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模型。
答案 0 :(得分:4)
你看过this resource了吗? 它声明你应该能够运行线程限制来找到最大线程数,并且可以通过编译glibc来调整它。
答案 1 :(得分:4)
使用NPTL线程将内核更新为更新版本(2.6.something)。
答案 2 :(得分:0)
这是使用Ubuntu Linux(1GB RAM)
dsm@localhost:~$ javac ThreadTest.java
dsm@localhost:~$ java ThreadTest
8113
dsm@localhost:~$ java -version
java version "1.6.0_07"
Java(TM) SE Runtime Environment (build 1.6.0_07-b06)
Java HotSpot(TM) Client VM (build 10.0-b23, mixed mode, sharing)
dsm@localhost:~$
答案 3 :(得分:0)
你可以试试JRockit JVM吗? IIRC,它有一个不同于Sun JVM库存的线程模型。
答案 4 :(得分:0)
/etc/security/limits.d/90-nproc.conf
中的设置可能会覆盖您的/etc/security/limits.conf
设置。这可能会导致系统以ulimit -u
中显示的不同方式执行。