Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java JVM对于GC';在对长Scala列表或流执行reduce()操作期间是否会发生异常?_Java_Scala_Stream_Garbage Collection_Jvm - Fatal编程技术网

Java JVM对于GC';在对长Scala列表或流执行reduce()操作期间是否会发生异常?

Java JVM对于GC';在对长Scala列表或流执行reduce()操作期间是否会发生异常?,java,scala,stream,garbage-collection,jvm,Java,Scala,Stream,Garbage Collection,Jvm,好的,让我看看能不能解释一下 我有一些代码将Java迭代器(恰巧来自Hadoop)包装到Scala流中,这样它就可以被我无法直接控制的客户机代码多次读取。使用此流完成的最后一件事是reduce()操作。流会记住它已经看到的所有项目。不幸的是,在某些情况下,迭代器将非常大,因此在其中存储所有项将导致内存不足错误。但是,一般来说,客户机代码需要多重迭代功能的情况与破坏内存的迭代器不同,如果确实存在这种情况,那不是我的问题 我想确保的是,我可以为需要它的代码提供记忆功能,但不能为不需要它的代码提供记忆

好的,让我看看能不能解释一下

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

我想确保的是,我可以为需要它的代码提供记忆功能,但不能为不需要它的代码提供记忆功能(特别是,对于从不查看流的代码)

Stream中reduce()的代码表示,它的编写方式允许流中已访问部分的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中的相关部分非常模糊,它说:

可访问对象是可以从任何活动线程在任何可能的连续计算中访问的任何对象

并解释说:

可以设计程序的优化转换,以减少可访问对象的数量,使其少于天真地认为可访问的对象的数量。例如,Java编译器或代码生成器可能会选择将不再使用的变量或参数设置为null,以使此类对象的存储可能更快地被回收

如果对象字段中的值存储在寄存器中,则会出现这种情况的另一个示例。然后程序可以访问寄存器而不是对象,并且不再访问对象。这意味着该对象是垃圾。请注意,只有当引用位于堆栈上而不是存储在堆中时,才允许进行这种优化

如果您的方法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;
        }
    };
}
public可调用foo(最终对象o){
返回新的可调用(){
公共字符串调用()引发InterruptedException{
字符串s=o.toString();
线程。睡眠(1000000);
返回s;
}
};
}

对象
o
在匿名
Callable
被收集之前无法收集,即使在
toString
调用之后从未使用过它,因为在
Callable
OK中有一个引用它的合成字段,这是非常有用的。你知道Sun的JVM在最近的版本中是否真的实现了这种优化吗?我相信是的。优化编译器无论如何都会中断源变量和堆栈帧位置之间的链接(变量有时会在寄存器中,不同的变量可能在不同的时间占据堆栈帧中的相同位置)。因此,为了让GC完全正确地进行,需要有相当精确的堆栈映射。但是,我是一个开发者!