当前位置: 首页 > 知识库问答 >
问题:

CompletableFuture链未完成->垃圾收集器?

梁华皓
2023-03-14

如果我有一个(或多个)可完成的未来尚未启动,并且在该方法上有几个,那么ApplyAsync()任何Of()方法。

垃圾收集器会移除所有这些吗?

如果在该链的末尾有一个< code > join()/< code > get()

也许我们需要更多关于连接上下文的信息()。

这种连接是线程中的最后一个命令,并且没有副作用。那么在这种情况下,线程仍然是活动的吗?- Java线程垃圾收集与否

无论如何,这是一个好主意,如果我确信(也许在尝试捕获中),那么将一个平衡药丸推向链条,我不会启动那个可完成链条,或者没有必要吗?

问题是因为这样?(https://bugs.openjdk.java.net/browse/JDK-8160402)

与此相关的一些问题:线程执行器何时被通知调度新任务?我想,当CompletableFuture转到下一个链接时?。所以我必须只进行内存泄漏,而不是线程泄漏?

编辑:我指的是一个尚未开始的CompletableFuture?

我指的是var < code > notStartedCompletableFuture = new CompletableFuture

我可以这样启动notStartedCompletableFuture:< code > notStartedCompletableFuture . complete(new Object);在程序流的后面或从另一个线程。

编辑2:更详细的示例:

AtomicReference<CompletableFuture<Object>> outsideReference=new AtomicReference<>();

final var myOuterThread = new Thread(() ->
{
    final var A = new CompletableFuture<Object>();
    final var B = new CompletableFuture<Object>();

    final var C = A.thenApplyAsync((element) -> new Object());
    final var D = CompletableFuture.anyOf(A, C);

    A.complete(new Object());

    // throw new RuntimeException();

    //outsideReference.set(B);

    ----->B.complete(new Object());<------ Edit: this shouldn't be here, i remove it in my next iteration

    D.join();

});

myOuterThread.start();

//myOutherThread variable is nowhere else referenced, it's sayed so a local variable, to point on my text on it^^

    < li >因此,在我示例中的正常情况下,我没有外部< br >参考。线程中的< code>CompletableFutures永远不会完成。通常情况下,GC可以安全地清除线程和其中的内容,即< code > competetablefutures 。但我不认为会发生这种事。 < li >如果我通过抛出异常来避免这种情况-

这里还有一个问题,如果线程通过等待join()而被阻塞,或者返回到线程池,我如何证明这种行为?,其中线程也“阻塞”?

共有3个答案

周健
2023-03-14
匿名用户

本答案仅针对“编辑2”中的3个后续问题。

  1. 所以在我的例子中,在正常情况下,我没有外部引用

我假设您指的是带有注释掉语句的版本。

线程中的< code>CompletableFutures永远不会完成。

不正确。首先,< code>A在这里完成:

A.complete(new Object());
    

下一个B在这里完成:

B.complete(new Object());

然后调用D.join()。因为D是一个anyOfstage,所以当 完成时,这就完成了 A已经完成,所以 D。join()可能不需要等待 CC异步应用函数,它也可以立即完成。

通常情况下,GC可以安全地清除线程和其中的内容,即< code>CompletableFutures。但我不认为会发生这种事。

当<代码>D时。join()返回,线程终止。此时,它的局部局部变量(ABCD>)将无法访问。

A像以前一样完成,但BCD没有。

但是,异常终止了线程,因此局部变量< code>A 、< code>B 、< code>C和< code>D变得不可访问。

三点:

>

  • 原子引用被分配到 B,因此 D 上的连接 () 不受影响。

    如上所述,对于变量< code>A 、< code>B 、< code>C和< code>D,假设的< code > join() on < code > outsidereference . value()是否发生并不重要。无论线程以何种方式终止,这些变量都变得不可访问。

    但是,您现在已经将对其中一个可完成未来对象的引用分配给了与线程具有不同生存期的变量。这可能意味着,在线程终止后,可完成未来对象将保持可访问状态。

  • 黄隐水
    2023-03-14

    如果线程对永远不会完成的CompletableFuture调用join() ,它将永远保持阻塞状态(除非被中断),并保留对该未来的引用。

    如果该未来是后代未来链(任务和执行器)的根,它还将保留对这些未来的引用,这些引用也将保留在内存中(以及所有可传递引用的对象)。

    通过 then*() 方法创建时,future 通常不会保存对其“父(s)”的引用,因此,如果没有其他引用,则通常应对其进行垃圾回收 - 但要注意这些引用,例如调用线程中的局部变量,对列表的引用

    屠嘉
    2023-03-14

    你似乎在纠结于CompletableFuture可能泄露的不同方式,这取决于你是如何创建它的。但是它是如何、在哪里、何时或为什么创建并不重要。唯一重要的是它是否仍然可以访问。

    垃圾收集器会移除所有这些吗?

    我们预计有两个地方会引用CompletableFuture:

    • Runnable(或其他)中,这将完成未来。
    • 在任何其他代码中,它会(在某个时候)尝试从未来获得最终价值。

    如果您有一个调用,那么ApplyAsync()anyOf(),则该调用的参数中包含引用 。如果调用仍然可以发生,那么对 Runnable的引用必须仍然可以访问。

    在你的例子中:

    var notStartedCompletableFuture = new CompletableFuture<Object>();
    

    如果变量notStartedCompletableFuture仍可被某些仍在执行的代码访问,则该CompletableFuture是可访问的并且不会被垃圾回收

    另一方面,如果< code > notStartedCompletableFuture 不再可访问,并且如果未来不再可通过其他路径到达,那么它将根本不可到达...并将成为垃圾收集的候选对象

    如果在该链的末尾有一个join()-

    这没什么区别。这都是基于可达性。(唯一的问题是当前活动的线程1始终是可达的,而不管对其Thread对象的任何其他引用如何。这同样适用于它的Runnable,以及从Runnable可达的其他对象。)

    但是值得注意的是,如果您在一个永远不会终止/完成的线程/ future上调用< code>join()或< code> get(),您将会阻塞当前线程,可能是永远阻塞。这就像线漏了一样糟糕。

    < sup>1 -线程从启动到终止都是“活动的”。

    线程执行器什么时候发出信号来安排新任务?

    这取决于你所说的“时间表”是什么意思。如果你的意思是,任务什么时候提交,那么答案就是调用< code>submit的时候。如果你的意思是,它实际上什么时候运行...它进入队列,当它到达队列头时运行,一个工作线程可以自由执行它。

    在< code>thenApplyAsync()和< code>all_of()的情况下,任务被提交(即< code>submit(...) call occurs)当相应的方法调用发生时。因此,举例来说,如果< code>thenApplyAsync是根据先前调用的结果调用的,那么该调用必须首先返回。

    这都是Java表达式求值的基本属性的结果...应用于用于构造阶段链的表达式

    通常,您不需要尝试/最终或尝试使用资源来清理潜在的内存泄漏。

    你所需要做的就是确保你没有在变量、数据结构等中保留对各种未来、阶段等的引用,这些引用在你的计算生命周期之外仍然是可访问的。如果你这样做了……这些引用很可能是泄漏的来源。

    线程泄漏不应该是您的关注点。如果您的代码未显式创建线程,则它们由执行器服务/池管理。

     类似资料:
    • 问题内容: 我有一个奇怪的疑问。我知道垃圾收集器有其自身的局限性。如果分配不正确,则可能导致应用程序以异常方式响应。 所以我的问题是,在每个活动结束时强制调用垃圾回收器()是良好的编程习惯吗? 更新资料 每个人都说调用system.gc()根本没有好处。然后,我想知道为什么它出现在这里。DVM将决定何时运行垃圾收集器。那么,该方法需要什么? 更新2 感谢社区的帮助。但老实说,我从此链接中获得了有关

    • 问题内容: 我想触发许多一次性异步CompletableFutures,例如: 理想情况下,可以在完成后将这些CompletableFutures进行垃圾回收。但是,由于我没有存储参考文献,因此是否有事先收集它们的风险? 问题答案: 您不是在显式地存储引用,而是在内部。该方法创建一个,然后向其提交引用的任务(如果您使用的是公共池)。在返回的变成了依赖于第一,因此也被引用。 一旦完成的执行,将第一个

    • Kubernetes 垃圾收集器的角色是删除指定的对象,这些对象曾经有但以后不再拥有 Owner 了。 注意:垃圾收集是 beta 特性,在 Kubernetes 1.4 及以上版本默认启用。 Owner 和 Dependent 一些 Kubernetes 对象是其它一些的 Owner。例如,一个 ReplicaSet 是一组 Pod 的 Owner。具有 Owner 的对象被称为是 Owner

    • 本文向大家介绍Java垃圾收集,包括了Java垃圾收集的使用技巧和注意事项,需要的朋友参考一下 示例 C ++方法-新增和删除 在像C ++这样的语言中,应用程序负责管理动态分配的内存所使用的内存。当使用new运算符在C ++堆中创建对象时,需要相应地使用delete运算符来处置该对象: 如果程序忘记了delete一个对象而只是“忘记”了该对象,则关联的内存将丢失给应用程序。这种情况的术语是内存泄

    • JavaScript 具有自动垃圾收集机制,也就是说,执行环境会负责管理代码执行过程中使用的内存。 而在C 和C++之类的语言中,开发人员的一项基本任务就是手工跟踪内存的使用情况,这是造成许多问题的一个根源。在编写JavaScript 程序时,开发人员不用再关心内存使用问题,所需内存的分配以及无用内存的回收完全实现了自动管理。这种垃圾收集机制的原理其实很简单:找出那些不再继续使用的变量,然后释放其

    • Java 15 使 ZGC、Z 垃圾收集器成为标准功能。它是 Java 15 之前的一个实验性功能。它是低延迟、高度可扩展的垃圾收集器。 ZGC 是在 Java 11 中作为一项实验性功能引入的,因为开发人员社区认为它太大而无法提前发布。 即使在机器学习应用程序等海量数据应用程序的情况下,ZGC 也具有高性能和高效工作。它确保在处理数据时不会因垃圾收集而长时间停顿。它支持 Linux、Window