現象
MACが
新しいネイティブスレッド
ウィンドウを作成できない
テストする前に、テストクラスを開始する前にJVMメモリを小さいサイズに調整してください。そうしないと、問題からコンピュータを簡単に実行できます。
アイデア:実行->構成の編集VMオプションの変更〜-Xms10M -Xmx10M
(-Xms10MJavaヒープメモリ初期化値-Xmx10MJavaヒープメモリ最大)
スレッド「メイン」の例外java.lang.OutOfMemoryError:Javaヒープスペース。
代码
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ルートJavaがGCを実行すると、GCルートから到達可能性が判断されます。一般的なGCルートは次のとおりです。
- システムクラスローダーまたはブートクラスローダーによってロードされるクラスオブジェクト、カスタムクラスローダーによってロードされるクラスは、必ずしもGCルートである必要はありません。
- アクティブスレッド
- スタック上のオブジェクト
- JNIスタック内のオブジェクト
- JNIのグローバルオブジェクト
- 同期に使用されているさまざまなロックオブジェクト
- システムクラスローダーなど、JVM自体が保持するオブジェクト。
メモリリークの原因を調査する場合、GCルートから導き出すことができます
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->
GC ROOTとして実行されるスレッドスレッドはGCではないため、主導権を握ってシャットダウンします。
FinalizableDelegatedExecutorServiceがfinalize関数を書き換えるため、newSingleThreadExecutorにはこの問題はありません。つまり、このクラスは、GCによってリサイクルされる前にスレッドプールのシャットダウンメソッドを実行します。
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();
}
}