2017-06-12 42 views
2

當我運行調用`(GET-線程綁定)`導致堆棧溢出

用戶>(得到線程綁定)

我看到

StackOverflowError clojure.lang.PersistentHashMap $ BitmapIndexedNode.index(PersistentHashMap.java:677)

這是一個新的項目lein new foo,在那裏我有一個單行

(DEF FOO 「Hello World」 的)

堆棧跟蹤已一再呼籲clojure.core/pr-onclojure.core/print-map等,但在觸發此事件的初始呼叫不可見。

回答

3

無論何時在REPL中計算表達式,最近三個表達式的結果都存儲在名爲*1*2*3的特殊線程綁定變量中。這些變量包含在由get-thread-bindings返回的映射中,因爲它們是線程綁定的。特別是,*1是所有線程限制變量的映射,其中一個值是var *1

這樣的循環引用可以存在於內存中,但是當您嘗試打印它到REPL時,您將遇到麻煩,因爲它看起來像一棵無限深的樹。相反,如果你想環顧(get-thread-bindings)返回的地圖,你將不得不稍微小心一點,看看那些不是無限的部分。例如,這裏就是我做仔細檢查,我的回答你的問題是正確的:

user=> (class (get-thread-bindings)) 
clojure.lang.PersistentHashMap 
user=> (keys (get-thread-bindings)) 
(#<Var: --unnamed--> #<Var: --unnamed--> #'clojure.core/*assert* #'clojure.core/*compile-path* #'clojure.core/*math-context* #'clojure.test/*test-out* #'clojure.core/*out* #<Var: --unnamed--> #'clojure.core/*2 #'clojure.core/*source-path* #'clojure.core/*err* #'clojure.core/*data-readers* #<Var: --unnamed--> #'clojure.core/*command-line-args* #<Var: --unnamed--> #'clojure.core/*warn-on-reflection* #'clojure.tools.nrepl.middleware.interruptible-eval/*msg* #'clojure.core/*read-eval* #'clojure.core/*default-data-reader-fn* #'clojure.core/*1 #'clojure.core/*unchecked-math* #'clojure.core/*e #'clojure.core/*file* #'clojure.core/*print-length* #'clojure.core/*3 #<Var: --unnamed--> #<Var: --unnamed--> #<Var: --unnamed--> #'clojure.core/*ns* #'clojure.core/*print-level* #<Var: --unnamed--> #<Var: --unnamed--> #<Var: --unnamed--> #'clojure.core/*in* #'clojure.core/*print-meta* #'clojure.tools.nrepl.middleware.session/*out-limit*) 
user=> (map (comp :name meta) (keys (get-thread-bindings))) 
(nil nil *assert* *compile-path* *math-context* *test-out* *out* nil *2 *source-path* *err* *data-readers* nil *command-line-args* nil *warn-on-reflection* *msg* *read-eval* *default-data-reader-fn* *1 *unchecked-math* *e *file* *print-length* *3 nil nil nil *ns* *print-level* nil nil nil *in* *print-meta* *out-limit*) 

圓形結構有點像Clojure的一個面向數據的語言痛苦的,因爲你已經習慣了能夠打印任何東西以查看它的全部內容,並且不能打印這些內容。但是,如上所述,您仍然可以通過查看他們是什麼班級,然後以某種與該班級一起工作的方式(例如,查看地圖,查看其關鍵字通常是一個好主意)來調查它們。

假設堆棧溢出不存在,或者你被困在沒有互聯網接入的空間站,你怎麼能自己發現*1現象?一旦你看到無法打印所有的get-thread-bindings,你可能已經發現它是一張地圖,然後環視四周的按鍵,看看它們中哪些在打印時會爆炸,哪些沒有。然後你可以進一步看看那個爆炸性的(*1),並發現它是另一張地圖,它包含另一個名爲*1的鍵,它的價值是另一張地圖......希望這會給你一些關於如何在未來調試類似問題的想法。

+0

感謝您的優秀解釋! – agam