当超出范围时,ExecutorService是否会收集垃圾? [英] Does an ExecutorService get garbage collected when out of scope?

查看:157
本文介绍了当超出范围时,ExecutorService是否会收集垃圾?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在问这个问题,因为我创建了很多执行器服务,虽然我可能已经在需要调查的地方有内存泄漏,但我认为最近对以下代码的更改实际上使其恶化了,因此我试图确认发生了什么:

  @FunctionalInterface 
public interface BaseConsumer extends Consumer< Path> {
@Override
default void accept(final Path path){
String name = path.getFileName()。toString();
ExecutorService service = Executors.newSingleThreadExecutor(runnable - > {
Thread thread = new Thread(runnable,documentId =+ name);
thread.setDaemon(true);
返回线程;
});
未来<?> future = service.submit(() - > {
baseAccept(path);
return null;
});
尝试{
future.get();
} catch(InterruptedException ex){
Thread.currentThread()。interrupt();
} catch(ExecutionException ex){
throw new RuntimeException(ex);
}
}

void baseAccept(final Path path)throws Exception;
}

然后这消费者< Path> 在另一个线程池中调用(通常)N = 2个线程,我不确定这是否相关。



问题是: ExecutorService服务超出范围获取垃圾回收一次 BaseConsumer#accept 已完成?

解决方案


ExecutorService服务是否超出范围并获取一次垃圾回收 BaseConsumer .accept()已完成?


是。

确实,关联的线程池也应该被垃圾收集......最终。

Executors.newSingleThreadExecutor() ExecutorService c> FinalizableDelegatedExecutorService 的一个实例。该类具有 finalize()方法,该方法在包装的 ExecutorService 上调用 shutdown() code>对象。如果所有未完成的任务实际终止,服务对象将关闭其线程池。



(AFAIK,这是未指定的,但它是根据源代码,在Java 6以后。)





是否添加了一个finally {service.shutdown (); future.get()有助于更快地获取资源吗? (不一定是垃圾收集服务对象)。

是的。调用 shutdown()会导致完成未完成任务后立即释放线程。这个过程立即开始,而如果你只是把它留给垃圾收集器,它将不会启动,直到调用终结器。



现在,如果资源只是普通 Java对象,这没关系。但在这种情况下,您要回收的资源是Java线程,并且具有关联的操作系统资源(例如本机线程)和非平凡的堆外存储器块。所以这可能是值得的。



但是如果你正在寻找优化这个,也许你应该创建一个长期生存的 ExecutorService 对象,并在多个消费者实例中共享。


I'm asking this question because I am creating a lot of executor services and while I may already have a memory leak somewhere that needs to be investigated, I think a recent change to the following code actually worsened it, hence I am trying to confirm what is going on:

@FunctionalInterface
public interface BaseConsumer extends Consumer<Path> {
    @Override
    default void accept(final Path path) {
        String name = path.getFileName().toString();
        ExecutorService service = Executors.newSingleThreadExecutor(runnable -> {
            Thread thread = new Thread(runnable, "documentId=" + name);
            thread.setDaemon(true);
            return thread;
        });
        Future<?> future = service.submit(() -> {
            baseAccept(path);
            return null;
        });
        try {
            future.get();
        } catch (InterruptedException ex) {
            Thread.currentThread().interrupt();
        } catch (ExecutionException ex) {
            throw new RuntimeException(ex);
        }
    }

    void baseAccept(final Path path) throws Exception;
}

Then this Consumer<Path> gets called on another thread pool with (usually) N=2 threads, I am not sure if that is relevant.

The question is: Does the ExecutorService service go out of scope and get garbage collected once BaseConsumer#accept has finished?

解决方案

Does the ExecutorService service go out of scope and get garbage collected once BaseConsumer.accept() has finished?

Yes.

Indeed, the associated thread pool should also be garbage collected ... eventually.

The ExecutorService that is created by Executors.newSingleThreadExecutor() an instance of FinalizableDelegatedExecutorService. That class has finalize() method that calls shutdown() on the wrapped ExecutorService object. Provided that all outstanding tasks actually terminate, the service object will shut down its thread pool.

(AFAIK, this is not specified. But it is what is implemented according to the source code, in Java 6 onwards.)


Does adding a finally { service.shutdown(); } in the try-catch around future.get() help in retrieving resources quicker? (not necessarily garbage collecting the service object).

Yes it does. Calling shutdown() causes the threads to be released as soon as the outstanding tasks complete. That procedure starts immediately, whereas if you just left it to the garbage collector it wouldn't start until the finalizer was called.

Now if the resources were just "ordinary" Java objects, this wouldn't matter. But in this case, the resource that you are reclaiming is a Java thread, and that has associate operating system resources (e.g. a native thread), and a non-trivial chunk of out-of-heap memory. So it is maybe worthwhile to do this.

But if you are looking to optimize this, maybe you should be creating a long-lived ExecutorService object, and sharing it across multiple "consumer" instances.

这篇关于当超出范围时,ExecutorService是否会收集垃圾?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆