"java.lang.OutOfMemoryError: unable to create new native thread" when using Thread.sleep(..)
"java.lang.OutOfMemoryError: unable to create new native thread" when using Thread.sleep(..)
我编写了一个简单的代码来模拟我在使用 ExecuterService 生成多个线程进行负载测试时遇到的问题。
代码:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class TestThreads {
public static void main(String[] args) {
class Testing implements Runnable {
@Override
public void run() {
Runnable r = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5000);
} catch(InterruptedException e1) {
Thread.currentThread().interrupt();
}
System.out.println("Running the inner thread");
}
};
Thread t = new Thread(r);
t.start();
System.out.println("After the thread has been started");
}
};
ExecutorService execService = Executors.newFixedThreadPool(20);
for (int i = 0; i < 1000000; i++) {
Testing testing = new Testing();
execService.execute(testing);
}
execService.shutdown();
try {
execService.awaitTermination(1000, TimeUnit.MICROSECONDS);
} catch(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
当我 运行 代码时,我得到多个 java.lang.OutOfMemoryError: unable to create new native thread
异常。如果我从测试 class 的 运行 方法中删除 Thread.sleep(5000)
,问题就会解决。我想知道为什么会这样?当池中的线程进入休眠状态时,ExecutorService 的行为如何(是否向池中添加另一个线程)?
现在,您的线程池创建的每个线程都会调用 运行 函数。每个 运行 您还创建了一个额外的新线程。因此,您将有 20 个活动线程 + 每个已经 运行 的线程有 1 个线程,并且这些内部线程没有使用线程池来帮助清理资源。
如果您不通过删除
创建内线程,则此代码应该有效
Thread t = new Thread(r);
t.start();
您只需使用 ExecutorService 管理 Testing
运行nable,这可确保一次只有 20 个 Testing
实例处于 运行ning 状态。这些线程完成得非常快,因为它们所做的只是用 Runnable
的匿名子类 TestThreads
启动另一个线程,然后退出。
您会在控制台中看到一百万行 "After the thread has been started"
,表明 for
循环已完成,
然后大约 5 秒后,您会看到一百万行 "Running the inner thread"
指示嵌套线程已完成,如果 您的系统允许 运行 一百万个线程。
因此,您要限制的只是新线程的启动速率,而不是线程数。
默认情况下,每个线程获得 512kb 的堆栈(您可以使用 -Xss
命令行选项将其更改为 java
)。
对于一百万个线程,这意味着您需要 1000000 * 512kb = 448Gb RAM。
我编写了一个简单的代码来模拟我在使用 ExecuterService 生成多个线程进行负载测试时遇到的问题。
代码:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class TestThreads {
public static void main(String[] args) {
class Testing implements Runnable {
@Override
public void run() {
Runnable r = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5000);
} catch(InterruptedException e1) {
Thread.currentThread().interrupt();
}
System.out.println("Running the inner thread");
}
};
Thread t = new Thread(r);
t.start();
System.out.println("After the thread has been started");
}
};
ExecutorService execService = Executors.newFixedThreadPool(20);
for (int i = 0; i < 1000000; i++) {
Testing testing = new Testing();
execService.execute(testing);
}
execService.shutdown();
try {
execService.awaitTermination(1000, TimeUnit.MICROSECONDS);
} catch(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
当我 运行 代码时,我得到多个 java.lang.OutOfMemoryError: unable to create new native thread
异常。如果我从测试 class 的 运行 方法中删除 Thread.sleep(5000)
,问题就会解决。我想知道为什么会这样?当池中的线程进入休眠状态时,ExecutorService 的行为如何(是否向池中添加另一个线程)?
现在,您的线程池创建的每个线程都会调用 运行 函数。每个 运行 您还创建了一个额外的新线程。因此,您将有 20 个活动线程 + 每个已经 运行 的线程有 1 个线程,并且这些内部线程没有使用线程池来帮助清理资源。
如果您不通过删除
创建内线程,则此代码应该有效Thread t = new Thread(r);
t.start();
您只需使用 ExecutorService 管理 Testing
运行nable,这可确保一次只有 20 个 Testing
实例处于 运行ning 状态。这些线程完成得非常快,因为它们所做的只是用 Runnable
的匿名子类 TestThreads
启动另一个线程,然后退出。
您会在控制台中看到一百万行 "After the thread has been started"
,表明 for
循环已完成,
然后大约 5 秒后,您会看到一百万行 "Running the inner thread"
指示嵌套线程已完成,如果 您的系统允许 运行 一百万个线程。
因此,您要限制的只是新线程的启动速率,而不是线程数。
默认情况下,每个线程获得 512kb 的堆栈(您可以使用 -Xss
命令行选项将其更改为 java
)。
对于一百万个线程,这意味着您需要 1000000 * 512kb = 448Gb RAM。