執行緒池OOM異常
現象
MAC
unable to creat new native thread
window
測試前 在啟動測試類之前先將JVM記憶體調整小一點,不然很容易將電腦跑出問題
在idea裡:Run -> Edit Configurations VM options修改成-Xms10M -Xmx10M
(-Xms10M Java Heap記憶體初始化值 -Xmx10M Java Heap記憶體最大值)
Exception in thread “main” java.lang.OutOfMemoryError: Java heap space。
程式碼
public static void main(String[] args) throws InterruptedException {
AtomicInteger i = new AtomicInteger(0);
for (; ; ) {
Executors.newFixedThreadPool(10).submit(() -> System.out.println(i.getAndIncrement()));
Thread.sleep(4);
}
}
迴圈建立執行緒池 而並沒有關閉執行緒池,導致執行緒池的例項會一直存在
原始碼
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE); // MAX_VALUE = 0x7fffffff
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
原因分析
Java常見的GC Root
Java 進行GC的時候會從GC root進行可達性判斷,常見的GC Root有如下:
- 通過System Class Loader或者Boot Class Loader載入的class物件,通過自定義類載入器載入的class不一定是GC Root
- 處於啟用狀態的執行緒
- 棧中的物件
- JNI棧中的物件
- JNI中的全域性物件
- 正在被用於同步的各種鎖物件
- JVM自身持有的物件,比如系統類載入器等。
在調查記憶體洩漏原因的時候可以根據GC Root來推導
當執行一個Runnable時,會先建立一個ThreadPoolExecutor中的內部類Worker物件,將這個Runnable物件作為Worker物件的一個成員變數
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
private volatile ThreadFactory threadFactory;
public ThreadFactory getThreadFactory() {
return threadFactory;
}
所以 當執行緒在執行的時候引用關係如下ThreadPoolExecutor->Worker->thread
一個執行的執行緒是作為GC ROOT的,不會被GC; 所以要主動shutdown
newSingleThreadExecutor不會有此問題,因為FinalizableDelegatedExecutorService 重寫了finalize函式,也就是說這個類會在被GC回收之前,先執行執行緒池的shutdown方法。
java.util.concurrent.Executors
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
static class FinalizableDelegatedExecutorService
extends DelegatedExecutorService {
FinalizableDelegatedExecutorService(ExecutorService executor) {
super(executor);
}
protected void finalize() {
super.shutdown();
}
}
相關文章
- JDK執行緒池異常處理方式JDK執行緒
- 執行緒池以及四種常見執行緒池執行緒
- Arthas | 定位線上 Dubbo 執行緒池滿異常執行緒
- 執行緒池異常處理的 5 中方式執行緒
- Java併發(五)執行緒池使用番外-分析RejectedExecutionException異常Java執行緒Exception
- 常見的四種執行緒池執行緒
- Java執行緒池二:執行緒池原理Java執行緒
- 執行緒和執行緒池執行緒
- 執行緒 執行緒池 Task執行緒
- 多執行緒【執行緒池】執行緒
- 執行緒池執行緒
- java執行緒池趣味事:這不是執行緒池Java執行緒
- java--執行緒池--建立執行緒池的幾種方式與執行緒池操作詳解Java執行緒
- 二. 執行緒管理之執行緒池執行緒
- Android多執行緒之執行緒池Android執行緒
- kuangshenshuo-多執行緒-執行緒池執行緒
- 多執行緒之手撕執行緒池執行緒
- java多執行緒9:執行緒池Java執行緒
- 執行緒池管理(1)-為什麼需要執行緒池執行緒
- Android執行緒池Android執行緒
- java 執行緒池Java執行緒
- Java執行緒池Java執行緒
- ThreadPool執行緒池thread執行緒
- 執行緒池 Executor執行緒
- 執行緒與執行緒池的那些事之執行緒池篇(萬字長文)執行緒
- 執行緒池之ScheduledThreadPoolExecutor執行緒池原始碼分析筆記執行緒thread原始碼筆記
- 執行緒池之ThreadPoolExecutor執行緒池原始碼分析筆記執行緒thread原始碼筆記
- SpringBoot執行緒池和Java執行緒池的實現原理Spring Boot執行緒Java
- Android程式框架:執行緒與執行緒池Android框架執行緒
- 執行緒池建立執行緒的過程執行緒
- 【Java】【多執行緒】執行緒池簡述Java執行緒
- Java執行緒池一:執行緒基礎Java執行緒
- Java多執行緒-執行緒池的使用Java執行緒
- ThreadPoolTaskExecutor 如果執行緒池預設的queue滿了,會觸發什麼異常thread執行緒
- 異常執行緒的相關複習(前)執行緒
- Java常見知識點彙總(⑭)——執行緒池Java執行緒
- 多執行緒執行任務時,某個執行緒拋異常,如何讓程式立即退出執行緒
- golang workpool,工作池,執行緒池Golang執行緒