9

我正在向Callablea 提交对象ThreadPoolExecutor,它们似乎一直存在于内存中。

使用 Eclipse 的 MAT 工具查看堆转储,可以看到Callable对象被 aFutureTask$Sync可调用变量引用。这FutureTask$Sync是由 aFutureTask同步变量引用的。这FutureTask是由FutureTask$Syncthis$0变量引用的。

我已经阅读了有关此内容(herehere和 on SO)的信息,似乎FutureTask可调用对象包含在ThreadPoolExecutor的 submit() 中永远持有对可调用对象的引用。

我感到困惑的是如何确保FutureTask收集垃圾,以便它不会继续将可调用对象保存在内存中,并保存可调用对象可能保存在内存中的任何内容?

只是为了提供有关我的特定情况的更多详细信息,我正在尝试以ThreadPoolExecutor一种允许在需要时取消所有提交的任务的方式来实现。我尝试了在 SO 和其他地方找到的几种不同方法,例如完全关闭执行程序(使用shutdown()shutdownNow())并保留期货返回列表submit()并对所有它们调用取消,然后清除期货列表。理想情况下,我希望不必将其关闭,并cancel()在需要时将其清除。

所有这些方法似乎都没有什么不同。如果我向池提交一个可调用的,它很有可能最终会留下来。

我究竟做错了什么?

谢谢。

编辑:

根据要求,这里是 ThreadPoolExecutor 的构造函数。

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
    super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}

经过进一步测试,我可以看到如果我让已经提交给 ThreadPoolExecutor 的任务完成,那么就没有泄漏。如果我尝试以任何方式取消它们,例如:

shutdownNow()

或者保存对未来的引用并稍后调用取消:

Future referenceToCancelLater = submit(task);
...
referenceToCancelLater.cancel(false);

或者通过使用以下方法将它们从队列中删除:

getQueue.drainTo(someList)

或者

getQueue.clear()

或循环保存对期货的引用并调用:

getQueue.remove(task)

任何这些情况都会导致 FutureTask 如上所述停留。

因此,所有这一切的真正问题是如何正确取消或从 ThreadPoolExecutor 中删除项目,以便 FutureTask 被垃圾收集并且不会永远泄漏?

4

4 回答 4

4

根据这篇文章,您可以在执行程序上调用purge 。

于 2012-12-16T01:03:10.873 回答
1

我什么都做不了,所以我想出了以下解决方案。这是一个粗略的概述:我在 ThreadPoolExecutor 中创建了一个数组,用于跟踪队列中的可运行对象。然后,当我需要取消队列时,我循环并在每个可运行对象上调用了一个取消方法。就我而言,所有这些可运行对象都是我创建的自定义类,它们的取消方法只是设置了一个取消标志。当队列启动下一个要处理的队列时,在 runnable 的运行中它会看到它被取消并跳过实际工作。

所以所有的runnables都会被快速地一一清除,因为它看到它被取消了。

可能不是最好的解决方案,但它适用于我并且不会泄漏内存。

于 2011-03-07T23:46:12.810 回答
1

作为一种解决方法,您可以执行以下操作:

class ClearingCallable<T> implements Callable<T> {
    Callable<T> delegate;
    ClearingCallable(Callable<T> delegate) {
        this.delegate = delegate;
    }

    T call() {
        try {
            return delegate.call();
        } finally {
            delegate = null;
        }
    }
}
于 2011-02-07T00:07:55.747 回答
0

参考:https ://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html

Future 表示异步计算的结果。如果使用方法 get 未检索到结果,则会发生内存泄漏!

如果您不想使用异步结果,请使用 Runnable 安装 Callable。

于 2016-07-05T02:11:46.737 回答