gpt4 book ai didi

java - 从垃圾收集中驱逐非直观的对象

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:35:03 25 4
gpt4 key购买 nike

我正在调试内存泄漏,不得不深入研究 CompletableFuture 的内部结构。有这段代码(CompletableFuture.uniComposeStage):

CompletableFuture<V> g = f.apply(t).toCompletableFuture();
...
CompletableFuture<V> d = new CompletableFuture<V>();
UniRelay<V> copy = new UniRelay<V>(d, g);
g.push(copy);
copy.tryFire(SYNC);
return d;

代码本身对我来说很清楚:应用一个返回 CompletionStage (g) 的函数,创建一个中继,最终将值传输到另一个 CompletableFuture (d) ,然后将其返回另一个 future (d)。我看到如下引用情况:

  • copy 引用了 dg(构造函数中没有魔法,只有字段赋值)
  • g 引用 copy
  • d 没有引用

只有 d 被返回,所以,事实上,gcopy 对我来说似乎都是内部方法变量,那(首先sight) 永远不应该离开方法并最终被 gc'。幼稚的测试和很久以前由经过验证的开发人员编写的事实都表明我错了并且遗漏了一些东西。是什么原因导致这些对象被垃圾回收遗漏?

最佳答案

在引用的代码中,没有任何东西阻止这些 future 的垃圾收集,也没有必要。这段有问题的代码适用于第一个CompletableFuture(this实例)已经完成,直接计算compose返回的CompletableFuture的场景功能尚未完成。

现在,有两种可能的情况

  1. 正在进行完成尝试。然后,最终将完成 future 的代码将持有对它的引用,并且在完成时,它将触发依赖阶段的完成(通过 g.push(copy) 注册)。在这种情况下,依赖阶段不需要持有对其前提阶段的引用。

    这是一个通用模式。如果存在链 x --will complete-→ y,则不会有从 yx 的引用。

  2. 没有其他引用 CompletableFuture 实例 g 并且 g 尚未完成。在这种情况下,它永远不会完成并且在内部持有对 g 的引用不会改变这一点。那只会浪费资源。

下面的示例程序将对此进行说明:

public static void main(String[] args) throws Throwable {
ReferenceQueue<Object> discovered = new ReferenceQueue<>();
Set<WeakReference<?>> holder = new HashSet<>();

CompletableFuture<Object> initial = CompletableFuture.completedFuture("somevalue");

CompletableFuture<Object> finalStage = initial.thenCompose(value -> {
CompletableFuture<Object> lost = new CompletableFuture<>();
holder.add(new WeakReference<>(lost, discovered));
return lost;
});
waitFor(finalStage, holder, discovered);
finalStage = initial.thenCompose(value -> {
CompletableFuture<Object> saved = CompletableFuture.supplyAsync(()-> {
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
return "newvalue";
});
holder.add(new WeakReference<>(saved, discovered));
return saved;
});
waitFor(finalStage, holder, discovered);
}
private static void waitFor(CompletableFuture<Object> f, Set<WeakReference<?>> holder,
ReferenceQueue<Object> discovered) throws InterruptedException {
while(!f.isDone() && !holder.isEmpty()) {
System.gc();
Reference<?> removed = discovered.remove(100);
if(removed != null) {
holder.remove(removed);
System.out.println("future has been garbage collected");
}
}
if(f.isDone()) {
System.out.println("stage completed with "+f.join());
holder.clear();
}
}

传递给 thenCompose 的第一个函数创建并返回一个新的未完成的 CompletableFuture 而不尝试完成它,不保存或存储对它的任何其他引用。相反,第二个函数通过 supplyAsync 创建 CompletableFuture,提供一个 Supplier,它会在一秒钟后返回一个值。

在我的系统上,它一直打印

future has been garbage collected
stage completed with newvalue

显示被遗弃的 future 不会被垃圾收集阻止,而另一个将至少保留到完成。

关于java - 从垃圾收集中驱逐非直观的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44530286/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com