20

Clojure プログラミング言語では、なぜこのコードは見事に合格するのでしょうか?

(let [r (range 1e9)] [(first r) (last r)])

これは失敗しますが:

(let [r (range 1e9)] [(last r) (first r)])

「頭を失う」というアドバイスについてですが、説明していただけますか?私はまだそれを消化することができません。

更新:
正しい答えを選ぶのは本当に難しいです.2つの答えは驚くほど有益です.
注: コード スニペットは「The Joy of Clojure」からのものです。

4

4 に答える 4

31

dfanRafałの回答を詳しく説明するために、時間をかけてYourKitプロファイラーで両方の式を実行しました。

JVM が動作しているのを見るのは魅力的です。最初のプログラムは非常に GC に適しているため、JVM はメモリの管理において真価を発揮します。

いくつかのチャートを描きました。

GCフレンドリー: (let [r (range 1e9)] [(first r) (last r)])

ここに画像の説明を入力

このプログラムはメモリ不足で実行されます。全体で 6 メガバイト未満。前述のように、これは非常に GC フレンドリーであり、多くのコレクションを作成しますが、そのために CPU をほとんど使用しません。

ヘッドホルダー: (let [r (range 1e9)] [(last r) (first r)])

ここに画像の説明を入力

これは非常にメモリを消費します。最大で 300 MB の RAM を使用できますが、それだけでは十分ではなく、プログラムは終了しません (JVM は 1 分以内に停止します)。GC は CPU 時間の最大 90% を占めています。これは、解放できるメモリを必死に解放しようとしますが、何も見つからないことを示しています (収集されるオブジェクトはほとんどまたはまったくありません)。

編集2 番目のプログラムがメモリ不足になり、ヒープ ダンプがトリガーされました。このダンプを分析すると、メモリの 70% が収集できなかった java.lang.Integer オブジェクトであることがわかります。別のスクリーンショットを次に示します。

ここに画像の説明を入力

于 2011-04-18T12:32:27.847 に答える
26

range必要に応じて要素を生成します。

の場合(let [r (range 1e9)] [(first r) (last r)])、最初の要素 (0) を取得し、10 億 - 2 の要素を生成し、それらを順次破棄してから、最後の要素 (999,999,999) を取得します。シーケンスの一部を保持する必要はありません。

の場合、(let [r (range 1e9)] [(last r) (first r)])を評価できるようにするために 10 億個の要素を生成しますが(last r)、後で を評価するために、生成しているリストの先頭を保持する必要もあり(first r)ます。そのため、何も捨てることができず、(おそらく) メモリが不足します。

于 2011-04-18T03:15:01.013 に答える
12

ここで本当に頭を悩ませているのは、シーケンスのバインディングです(値からシーケンス全体を評価することはできないためr、既に評価された ではありません)。(first r)

最初のケースでは、 が評価されるとバインディングは存在しなくなります。これは、評価(last r)する式がなくなるrためです。2 番目のケースでは、まだ評価されていない の存在は、(first r)評価者が へのバインディングを維持する必要があることを意味しrます。

違いを示すために、これは OK と評価されます。

user> (let [r (range 1e8) a 7] [(last r) ((constantly 5) a)])

[99999999 5]

これは失敗しますが:

(let [r (range 1e8) a 7] [(last r) ((constantly 5) r)])

次の式は を(last r)無視しますrが、エバリュエーターはそれほどスマートではなく、 へのバインディングを維持rするため、シーケンス全体が維持されます。

編集: Rich Hickey が上記のケースで head への参照をクリアするメカニズムの詳細を説明している投稿を見つけました。ここにあります:地元の人々の清算に関するリッチ・ヒッキー

于 2011-04-18T12:19:27.293 に答える
2

技術的な説明については、http://clojure.org/lazyにアクセスしてください。アドバイスはセクションに記載されていますDon't hang (onto) your head

于 2011-04-19T09:56:12.210 に答える