【问题标题】:Does laziness prevent garbage collection in java?懒惰会阻止Java中的垃圾收集吗?
【发布时间】:2022-01-11 12:49:30
【问题描述】:

考虑这个类:

class Stream<A>{
        Supplier<A> headSupplier;
        Supplier<Stream<A>> tailSupplier;
        public Stream<A> take(int n) {
            return n <= 0
                    ? empty()
                    : new Stream(this.headSupplier, () -> this.tail().take(n - 1));
        }
        //other code
    }

现在考虑这个方法:

 Stream<Integer> someMethod(){
        Stream<Integer> A = ...;
        return A.take(10);
    }

还有另一种方法:

Stream<Integer> B = someMethod();

someMethod() 返回时会发生什么,对A 的引用是否仍保留在内存中 因为当我们在B 上调用tail() 时需要它?如果是这样,这不是内存泄漏或效率低下吗?我们如何防止它?

【问题讨论】:

  • 一般来说,与惰性求值相关的内存消耗很难预测。内存泄漏可能会出现 * 如果引用被持有太久 * 如果不必要的引用保持活动状态 * 如果创建了不必要的表达式(嵌套的空函数)。您可以将惰性求值视为表达式求值和内存使用之间的权衡。

标签: java functional-programming garbage-collection


【解决方案1】:

在此设计中,创建 Stream 对象保留对其头部供应商的引用。所以,是的,只要B 流对象是活动的,A 对象就可以被视为活动的。

从概念的角度来看它:在您的示例中,您的 Stream 类(基本上)是某种集合。是的,集合保留对它们包含的事物的引用。因此,只要拥有“收集”存在,引用的“包含”对象就不会受到垃圾收集。

所以这不是内存泄漏:如果您决定在代码中创建B,那么您必须了解B 中的内容来自哪里。

【讨论】:

  • 但是take 方法的意义何在?如果我将A 的所有不需要的元素保留在内存中?从这个角度来看,我将其视为内存泄漏(或效率低下,确切的称呼)
  • 嗯,这个问题应该交给设计非标准 Stream 类的那本书的作者。如前所述,仅对我而言,该课程的名称具有误导性。它似乎打算成为某种收藏品。但即便如此:java 流也会一直存在,直到您调用终止操作。并且如前所述:当B 被认为已死时,可以收集它持有的引用。
  • @User0123 你可以想像fluid builder pattern中的setter方法之类的中间流操作。流就像一个尚未确定的结果的构建器(甚至可以为空)。调用take 方法配置流,但在执行终端操作(想想调用builder.build())之前,没有可见的外部效果。
猜你喜欢
  • 2015-05-04
  • 2015-10-08
  • 2010-09-22
  • 1970-01-01
  • 2013-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多