ExecutorService在频繁关闭后导致内存不足异常

时间:2015-09-29 15:00:53

标签: java multithreading concurrency executorservice

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class ExecutorServiceTest {

    public static void main(String args[]) {
        new ExecutorServiceTest();
    }

    public ExecutorServiceTest() {
        while (true) {
            action();
        }
    }

    public String action() {
        String string = "";
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<String> future = executor.submit(new Callable() {
            @Override
            public String call() {
                return randomString();
            }
        });
        try {
            string = future.get(1, TimeUnit.MILLISECONDS);
        } catch (InterruptedException | ExecutionException | TimeoutException ex) {

        }
        future.cancel(true);
        executor.shutdownNow();
        return string;
    }

    public String randomString() {
        return "asdhkashdkjshakdasdsahdka";
    }

}

如果打开任务管理器窗口然后运行此类,您会注意到Java立即使用了大量内存。我彻底搜索并调试了类,但找不到内存泄漏。

是什么导致future.get(1, TimeUnit.MILLISECONDS);耗尽所有系统内存然后崩溃?

2 个答案:

答案 0 :(得分:6)

ThreadPoolExecutor类具有非空finalize()方法(执行池关闭),因此在进行垃圾收集时,它首先进入终结器队列(基本上是链表)并由分开&#34;终结者&#34;线。即使池没有活动任务,关闭它也很慢。根据硬件,操作系统和运行条件,新的终结器的添加速度可能比Finalizer线程处理的速度快,因此您可能会期望内存不断增长。通常,您不应该过快地创建和关闭执行程序。

答案 1 :(得分:0)

我认为罪魁祸首就在这里:

while (true) {
    action();
}

这会积极地产生新线程(这是一项昂贵的操作)而且,恕我直言,这会导致内存问题和崩溃。

另外,我认为这是使用单线程执行程序的一个不好的例子。它更适合在单个后台线程中串行执行任务。如果需要添加大量必须同时执行的新任务,最好使用线程池。控制工作线程数将阻止程序内存不足。

工作代码:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class ExecutorServiceTest {

    ExecutorService executor = Executors.newSingleThreadExecutor();

    public static void main(String args[]) {
        new ExecutorServiceTest();
    }

    public ExecutorServiceTest() {
        while (true) {
            action();
        }
    }

    public String action() {
        String string = "";
        if (executor.isShutdown()) {
            Future<String> future = executor.submit(new Callable() {
                @Override
                public String call() {
                    return randomString();
                }
            });
            try {
                string = future.get(1, TimeUnit.MILLISECONDS);
            } catch (InterruptedException | ExecutionException | TimeoutException ex) {
                System.out.println(ex);
            }
            future.cancel(true);
            executor.shutdownNow();
        }
        return string;
    }

    public String randomString() {
        return "asdhkashdkjshakdasdsahdka";
    }

}