gpt4 book ai didi

java - 在长 Scala 列表或 Stream 上进行 reduce() 操作期间,Java JVM 关于 GC 的智能程度如何?

转载 作者:行者123 更新时间:2023-11-30 04:39:52 25 4
gpt4 key购买 nike

好吧,让我看看是否可以解释一下。

我有一些代码将 Java 迭代器(碰巧来自 Hadoop)包装在 Scala Stream 中,以便我无法直接控制的客户端代码可以多次读取它。此 Stream 完成的最后一件事是 reduce() 操作。 Stream 会记住它已经看到的所有项目。不幸的是,在某些情况下迭代器会非常大,因此在其中存储所有项目将导致内存不足错误。但是,一般来说,客户端代码需要多次迭代功能的情况与内存消耗迭代器的情况不同,如果确实存在这种情况,那不是我的问题。

我想确保的是,我可以为需要它的代码提供内存功能,但不能为不需要它的代码提供内存功能(特别是对于根本不查看流的代码)。

Stream 中的 reduce() 代码表示,它的编写方式允许在减少时对 Stream 已访问的部分进行 GC。因此,如果我能确保这确实发生,那就没问题了。但在实践中我怎样才能确保这种情况发生呢?特别是,如果函数 A 创建流并将其传递给函数 B,函数 B 将流传递给函数 C,然后函数 C 调用 reduce(),那么函数 A、B 和 C 中对流的引用仍然存在吗? ?在所有这些情况下,这三个函数中的任何一个都不会进一步使用流,尽管调用不一定是尾递归的。 JVM是否足够聪明,可以确保在调用reduce()时函数A、B和C的引用计数为0,以便GC发生?本质上,这意味着 JVM 在函数 A 中注意到它对该项所做的最后一件事是调用函数 B,因此它在调用 B 的同时消除了自己的句柄,同样对于 B 到 C,以及 C 到 reduce( )。

如果这可以正常工作,那么如果 A、B 或 C 有一个保存该项目的局部变量,它也可以工作吗? (同样,之后不会使用它。)这是因为在不使用本地变量的情况下正确编码会更加棘手。

最佳答案

一个在作用域内但永远不会被读取的变量是。出于垃圾收集的目的,JVM 可以自由地忽略死变量;仅由死变量指向的对象是无法访问的,并且可以被收集。 JLS 的相关位很模糊地是 §12.6.1 Implementing Finalization ,其中表示:

A reachable object is any object that can be accessed in any potential continuing computation from any live thread.

并解释说:

Optimizing transformations of a program can be designed that reduce the number of objects that are reachable to be less than those which would naively be considered reachable. For example, a Java compiler or code generator may choose to set a variable or parameter that will no longer be used to null to cause the storage for such an object to be potentially reclaimable sooner.

Another example of this occurs if the values in an object's fields are stored in registers. The program may then access the registers instead of the object, and never access the object again. This would imply that the object is garbage. Note that this sort of optimization is only allowed if references are on the stack, not stored in the heap.

如果你的方法 A 只有引用流的死变量,那么它不会阻碍它的收集。

但请注意,这意味着局部变量:如果您有引用流的字段(包括来自封闭嵌套类的方法的封闭局部变量),则这不适用;我不认为 JVM 可以将它们视为已死的。换句话说,这里:

public Callable<String> foo(final Object o) {
return new Callable<String>() {
public String call() throws InterruptedException {
String s = o.toString();
Thread.sleep(1000000);
return s;
}
};
}

在收集匿名 Callable 之前,无法收集对象 o,即使它在 toString 调用之后从未使用过,因为是在 Callable 中引用它的合成字段。

关于java - 在长 Scala 列表或 Stream 上进行 reduce() 操作期间,Java JVM 关于 GC 的智能程度如何?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12571252/

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