テールコールの最適化を実装するために、jvmは何を犠牲にしなければなりませんか?
-
06-07-2019 - |
質問
人々は、clojureの実装は、末尾呼び出しの最適化がないという制限-clojureの実装ではなくjvmの制限を除いて優れていると言います。
http://lambda-the-ultimate.org/node/2547
TCOをPythonに実装すると犠牲になると言われています
- スタックトレースダンプ、および
- デバッグの規則性。
テールコールの最適化の重要性とPythonが必要な理由を説明してください
TCOのjvm実装にも同じ犠牲を払わなければなりませんか?他に何かを犠牲にする必要がありますか?
解決
異なる(ilの指示が既に存在するという点で)が、.Net 64ビットJITチームは、すべてのテールコールを尊重するために通過する必要がありました。
特にコメントを呼びます:
デメリットは、最適化されたコードをデバッグまたはプロファイリングする必要がある場合、いくつかのフレームが欠落しているように見えるコールスタックに対処する準備ができていることです。
JVMがこれを回避できる可能性は非常に低いと思います。
テールコールの最適化が要求された状況では、JITはスタックオーバーフローを回避するために必要であると想定する必要があり、これはデバッグビルドでオフにできるものではありません。興味深い部分に到達する前にクラッシュする場合、デバッグにはあまり使用されません。 「最適化」は実際には永続的な機能であり、それによって影響を受けるスタックトレースの問題です。
プログラマーが概念的にスタック操作であると説明/理解する操作(たとえば、関数を呼び出す)を行うときに実際のスタックフレームの作成を回避する最適化は、本質的に表示されるものとの間に切断を引き起こすことを指摘する価値がありますスタックトレースと現実をデバッグ/提供するときにユーザーに提供します。
これは、操作を記述するコードが操作を実行するステートマシンのメカニズムからさらに分離されるため、避けられません。
他のヒント
はい、通常、TCOを実装すると完全なスタックトレースを取得できなくなります。 TCOの重要な点は、追加のスタックフレームの作成を避けることであるため、これは避けられません。
Clojureにはスタックを消費しない「繰り返し」があります。現在のJVMバージョンでこの制約を回避する機能。
例:
(defn triangle [n accumulator]
(if
(<= n 0)
accumulator
(recur (dec n) (+ n accumulator))))
(triangle 1000000 0)
=> 500000500000 (note stack does not explode here!)