2013-02-21 5 views
8

this SO threadには、大規模なコレクションにseqへの参照を保存すると、コレクション全体がガベージコレクションされないことが分かりました。Clojureで `seq`を使うのはいつか?

最初に、そのスレッドは2009年です。これは「現代の」Clojure(v1.4.0またはv1.5.0)ではまだ当てはまりますか?

第2に、この問題はレイジーシーケンスにも当てはまりますか?たとえば、(def s (drop 999 (seq (range 1000))))は、ガベージコレクタがシーケンスの最初の999要素をリタイアできるようにしますか?

最後に、大きなコレクションでこの問題を回避する方法はありますか?言い換えれば、例えば、1000万要素のベクトルがあれば、消費された部分がガベージコレクションされるような方法でベクトルを消費することができますか? 1000万要素のハッシュマップがあったらどうなりますか?

私はかなり大きなデータセットで操作しているので、不要なオブジェクトをガベージコレクションできるように、オブジェクトへの参照を保持しないように注意する必要があります。その通りですが、場合によってはjava.lang.OutOfMemoryError: GC overhead limit exceededエラーが発生します。

+0

@cgrandの例 '(drop 999990(vec(range 1000000)))'は、介在するベクトルと 'subvec'toringの振る舞いによるものだと思います。私は怠惰な 'cons'edシーケンスがこれをするだろうとは思わない。サブベクトルを保持したままベクターを解放する必要がある場合は、サブベクトルを新しいベクターにコピーすることができます。非常に興味深い質問ですが、私も答えを見るのを待っています! –

答えて

6

Clojureは、シーケンスの「先頭を保持」すると、すべてをメモリに保持することが常に強制されます。これは選択肢がありません:あなたはまだそれを参照しています。

しかし、「GCオーバーヘッド限界に達しました」はメモリ不足エラーと同じではありません。つまり、GCをトリックするようにオブジェクトを非常に高速に作成および破棄している架空のワークロードを実行している可能性がありますそれが過負荷になっていると考えることになります。

参照:

あなたが処理されている項目に実際の作業負荷をかけた場合、私はあなたがこのエラーがこれ以上起こらないことがわかります疑います。この場合、使用可能なメモリよりも大きいレイジーシーケンスを簡単に処理できます。

しかし、ベクトルやハッシュマップなどのコンクリートコレクションは、問題はありません。これらは怠惰ではないため、常にメモリに完全に保持する必要があります。あなたはメモリよりも大きなデータセットを持っている場合は、あなたのオプションが含まれます:

  • 使用怠惰なシーケンスをヘッド
  • 使用遅延読み込みをサポートして専門的なコレクションに保有していない
  • (Datomicは、私は信じている。このようないくつかの構造を使用しています)
  • データをイベントストリームとして扱う(ストームのようなものを使用)
  • データをチャンクに分割して一度に1つずつ処理するカスタムコードを記述します。
+0

ありがとう、mikera、これは役に立ちます。私はStormとDatomicをチェックするのを楽しみにしています。 –

0

バインディングの中でシーケンスの先頭を保持していれば、正しいと判断でき、gc'dできません(それはClojureのすべてのバージョンにあります)。大量の結果を処理している場合、なぜ頭を握る必要がありますか?

そうです、はい! lazy-seq実装では、既に '処理済み'でバインディング内から直接参照されていない部分をgcできます。あなたがシーケンスの先頭を握っていないことを確認してください。

+1

私は問題は、いくつかのサブコレクションは、元のものにバインディングがない場合でも、オリジナル全体への参照を保持していると思いますか? 'subvec'のドキュメンテーションは、例えば..."結果ベクトルはオリジナルと構造を共有し、トリミングは行われません。 "私はこれを使って 'subvec'が元​​のものを覆い、ちょうどオフセットを再マップすることを意味するが、私はClojureの内部にはあまり入っていない。 –

+0

@ A.Webb、私はあなたが正しいと考えて、上記の例から作成されたサブベクトルは、コレクションの先頭を保持します。 (999990(lazy-seq(range 1000000))))は、(少なくとも私の理解から) –

+0

シーケンスを 'lazy-seq'でラップすることについての魔法はありません。 'list *'ラッパーを同じものに置き換えます。 (また、 'range'はすでに怠惰です。) –

関連する問題