我们假设我们有以下代码:
List<Future<?>> runningTasks;
ExecutorService executor;
...
void executeTask(Runnable task){
runningTasks.add(executor.submit(task));
}
我的问题是:
runningTasks
是否包含对task
对象的引用?答案 0 :(得分:2)
在执行者或Future
对象持有对它的引用之前是一个实现细节。因此,如果您的任务使用大量内存而不必担心内存使用情况,则应在任务完成之前明确清理任务。
如果查看ThreadPoolExecutor
的{{3}},您可以看到实际上底层Future
对象实际上无限期地保留了对底层可调用对象的引用(即只要存在对Future
对象的强引用,可调用的不能是GCd)。对于1.7也是如此。从1.8开始,对的引用被删除。但是,您无法控制将运行ExecutorService
任务的实现。
使用WeakReference
实际上应该作为Future
工作,因此Callable
对象可以在任务完成后成为GCd,并且ExecutorService
的合理实现应该失去参考当任务完成时。严格来说,这仍然取决于ExecutorService的实现。此外,使用WeakReference可能会增加惊人的大开销。只需明确清理占用大量内存的任何对象,你会好得多。相反,如果你没有分配大型物体,那我就不用担心了。
当然,如果你不断删除任何期货而不断添加期货,那么这个讨论就完全不同于你将会遇到的内存泄漏。如果你这样做,即使使用WeakReference
也无济于事;你还会有内存泄漏。为此,只需遍历列表并删除已经完成的未来,因此没有用。每次都这样做真的很好,除非你有一个非常大的队列大小,因为这很快。
答案 1 :(得分:-1)
Future
。如果您使用ScheduledFuture
,则可能会遇到内存泄漏问题,因为ScheduledFuture.cancel()
或Future.cancel()
通常不会通知其Executor
它已被取消并且保留在队列直到执行时间到了。对于简单的期货来说这不是什么大问题,但对于ScheduledFutures
来说可能是个大问题。它可以在那里停留数秒,数分钟,数小时,数天,数周,数年或几乎无限期,具体取决于计划的延迟。
有关内存泄漏情况及其解决方案示例的更多详细信息,请参阅我的其他answer。