垃圾收集—java中的“标记和扫描”行为,特别是对于将来的对象

pftdvrlh  于 2021-06-29  发布在  Java
关注(0)|答案(2)|浏览(249)

我想知道 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);
  }
}
gab6jxml

gab6jxml1#

“submit”意思是给某人一些东西,在这种情况下,你给出的是一段代码(以 Callable )到 ExecutorService 以便以后执行。作为回报,该方法返回 Future 对象,完成后将使用结果更新。
为了 ExecutorService 更新 Future 对象,它需要按住 Future 对象,以及代码引用( Callable ).
因此 ExecutorService 保留对两个 Callable 对象和 Future 对象,直到作业完成。这些引用使两个对象都可以访问,从而防止对象被垃圾收集。
因为你的代码丢弃了返回的 Future 对象,该对象将在作业完成后立即成为gc的合格对象,但不能在此之前。

ryevplcw

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 .
然后工作线程调用 completeFuture 提供结果。
最后,一些东西通常会调用 Future.get 为了得到结果(但不是你的例子。)
以便执行步骤6。为了工作 CompletableFuture 必须仍然可以到达。在所有引用丢失或丢弃之前,它不会被丢弃。当然,在第6步完成之前。
一句话:java处理 Future 就像其他(正常的)物体一样。别担心。如果有什么需要它,它不会消失。
1-当您考虑、最终确定和 Reference 类型。但同样的一般原则也适用。如果任何代码仍然可以看到一个对象,它将不会被删除。

相关问题