1

OK、説明できるかどうか見てみましょう。

Javaイテレーター(Hadoopから)をScalaストリームにラップするコードがあります。これにより、直接制御できないクライアントコードによって、Javaイテレーターを複数回読み取ることができる可能性があります。このStreamで最後に行われるのは、reduce()操作です。Streamは、すでに表示されているすべてのアイテムを記憶しています。残念ながら、状況によってはイテレータが非常に大きくなるため、すべてのアイテムをイテレータに格納すると、メモリ不足エラーが発生します。ただし、一般に、クライアントコードが複数の反復機能を必要とする状況は、メモリを破壊するイテレータと同じではありません。そのような場合が存在する場合、それは私の問題ではありません。

私が確実にしたいのは、メモ化機能を必要とするコードには提供できるが、それを必要としないコード(特に、ストリームをまったく見ないコード)には提供できないことです。

Streamのreduce()のコードは、Streamのすでにアクセスされた部分のGCが発生することを可能にする方法で記述されていることを示しています削減します。ですから、これが実際に起こることを確認できれば、大丈夫です。しかし実際には、これが確実に行われるようにするにはどうすればよいでしょうか。特に、関数Aがストリームを作成して関数Bに渡し、関数Bがストリームを関数Cに渡し、関数Cがreduce()を呼び出す場合、関数A、B、およびCにあるストリームへの参照はどうでしょうか。 ?これらすべての場合、呼び出しは必ずしも末尾再帰である必要はありませんが、3つの関数のいずれでもストリームをそれ以上使用することはありません。JVMは、reduce()が呼び出されたときに関数A、B、およびCからの参照カウントが0になるように十分にスマートであり、GCが発生する可能性がありますか?基本的に、これは、JVMが関数Aで、アイテムに対して最後に行うことは関数Bの呼び出しであることに気付くため、Bを呼び出すと同時に自身のハンドルを削除することを意味します。

これが適切に機能する場合、A、B、またはCにアイテムを保持するローカル変数がある場合にも機能しますか?(これも、後で使用されません。)これは、ローカル変数を使用せずにこれを適切にコーディングするのがかなり難しいためです。

4

1 に答える 1

2

スコープ内にあるが読み取られることのない変数はdeadです。JVM は、ガベージ コレクションの目的で無効な変数を自由に無視できます。死んだ変数によってのみ指されているオブジェクトは到達不能であり、収集される可能性があります。JLS の関連するビットは、あいまいですが、§12.6.1 ファイナライズの実装であり、次のように述べています。

到達可能なオブジェクトは、任意のライブ スレッドから潜在的に継続する計算でアクセスできる任意のオブジェクトです。

そして次のように説明しています。

プログラムの最適化変換を設計して、到達可能なオブジェクトの数を単純に到達可能と見なされるオブジェクトの数より少なくすることができます。たとえば、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;
        }
    };
}

オブジェクトは、呼び出し後に使用されることはありませんがo、匿名が収集されるまで収集できません。.CallabletoStringCallable

于 2012-09-24T19:36:31.300 に答える