今天定位了一个内存泄露的问题,错误如下:
Exception in thread"http-exec-24" java.lang.OutOfMemoryError: unable to create newnative thread
众所周知,内存泄露和内存溢出JVM都会抛出OutOfMemoryError异常。内存泄露是由于程序编码有缺陷,通过修改Java代码可以修复。内存溢出则是由于JVM运行时需要占用的内存大于JVM启动参数所设置的。
看下现有代码:
/***
* 测试线程池关闭。
* @authorjim
*
*/
public class ThreadPoolTest {
/**
* 启动线程池,运行任务。
*/
public static voidpoolExecute(){
int size =10;
ExecutorService executor =Executors.newFixedThreadPool(size);
for (int i = 0;i < size; i ++){
executor.execute(newRunnable() {
@Override
publicvoid run(){
}
});
}
}
public static voidmain(String[] args){
poolExecute();
try {
// 主线程挂起
CountDownLatch latch = newCountDownLatch(1);
latch.await();
} catch(InterruptedException e) {
}
}
}
一眼看去貌似没有问题,poolExecute返回后,executor对象也应该销毁了。
用jconsole连接到程序,发现由ExecutorService启动的线程并未关闭,多次调用poolExecute后就会导致残留太多的线程。
查看Executors.newFixedThreadPool方法如下:
public static ExecutorService newFixedThreadPool(intnThreads) {
return newThreadPoolExecutor(nThreads, nThreads,
0L,TimeUnit.MILLISECONDS,
newLinkedBlockingQueue<Runnable>());
}
其返回了一个ThreadPoolExecutor对象。
查看ThreadPoolExecutor的实现,发现线程启动后会循环从Worker队列中取出Worker执行,而Worker队列采用的是LinkedBlockingQueue,当队列中没有要执行的Worker线程会等待,即线程无法结束,导致线程无法回收。若要结束线程,需要调用ThreadPoolExecutor.shutdown()方法,停止线程。
还有一种方法可以通过调用ThreadPoolExecutor. allowCoreThreadTimeOut(true)允许超时自动关闭。
更多ThreadPoolExecutor的介绍请参考Java API。