我想知道 Future
对象,该对象未绑定到命名变量。
我了解到java采用mark&sweep风格的垃圾收集。在这种情况下,任何未命名的对象都可以立即从堆中删除。所以我想知道 Future
可能会在 Runnable
完成,否则内存可能永远不会被释放。
任何信息都会有帮助,谢谢!
class Main {
void main() {
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> { return true; }); // not bind to variable
Thread.sleep(1000);
}
}
2条答案
按热度按时间gab6jxml1#
“submit”意思是给某人一些东西,在这种情况下,你给出的是一段代码(以
Callable
)到ExecutorService
以便以后执行。作为回报,该方法返回Future
对象,完成后将使用结果更新。为了
ExecutorService
更新Future
对象,它需要按住Future
对象,以及代码引用(Callable
).因此
ExecutorService
保留对两个Callable
对象和Future
对象,直到作业完成。这些引用使两个对象都可以访问,从而防止对象被垃圾收集。因为你的代码丢弃了返回的
Future
对象,该对象将在作业完成后立即成为gc的合格对象,但不能在此之前。ryevplcw2#
我了解到java采用mark&sweep风格的垃圾收集。
这基本上是不正确的。大多数现代java垃圾收集器都不是mark&sweep。它们主要是复制收集器,通过将对象疏散(复制)到标记的“到”空间来工作。而且大多数java垃圾收集器也是分代的。
oracle发布了大量关于java垃圾收集器及其工作方式的资料。关于这个问题也有很好的教科书。
在这种情况下,任何未命名的对象都可以立即从堆中删除。
名字与此无关。引用不是名称,也不是变量。只有当gc发现java对象不可访问时,才会删除它们;i、 如果没有代码就永远找不到它们。此外,它们不会立即被删除,甚至(必须)在下一次gc运行时被删除。
所以我想知道
Future
可能会在Runnable
完成,否则内存可能永远不会被释放。(这是一个
Callable
而不是一个Runnable
. 一Runnable
不会返回任何内容。)答案是不会的。
生命周期是这样的:
你打电话来
submit
路过Callable
.一
CompletableFuture
已创建。这个
CompletableFuture
以及Callable
添加到执行者的队列中。这个
CompletableFuture
返回给调用者(在你的情况下,打电话的人会把它扔掉。)稍后,工作线程将执行
Future
以及Callable
从队列中执行Callable
.然后工作线程调用
complete
上Future
提供结果。最后,一些东西通常会调用
Future.get
为了得到结果(但不是你的例子。)以便执行步骤6。为了工作
CompletableFuture
必须仍然可以到达。在所有引用丢失或丢弃之前,它不会被丢弃。当然,在第6步完成之前。一句话:java处理
Future
就像其他(正常的)物体一样。别担心。如果有什么需要它,它不会消失。1-当您考虑、最终确定和
Reference
类型。但同样的一般原则也适用。如果任何代码仍然可以看到一个对象,它将不会被删除。