2016-08-06 82 views
2

Hier ist eine Namensfrage für diese Site.Clojure Core Cache Stackoverflow

Warum wirft dieses Codeelement eine StackOverflow-Ausnahme in Clojure?

(require [clojure.core.cache :as cache]) 

(def C (atom (cache/fifo-cache-factory {} :threshold 1E7))) 

(doseq [i (range 1 1E6)] 
    (swap! C cache/miss i i)) 

Und ich bekomme Folgendes. Ich habe in meinem Code keine Concat-Operationen ausgeführt. Dies ist sehr reproduzierbar. Ich verwende clojure 1.7 auf Java 8.

Caused by: java.lang.StackOverflowError 
    at clojure.lang.RT.seq(RT.java:507) 
    at clojure.core$seq__4128.invoke(core.clj:137) 
    at clojure.core$concat$fn__4215.invoke(core.clj:691) 
    at clojure.lang.LazySeq.sval(LazySeq.java:40) 
    at clojure.lang.LazySeq.seq(LazySeq.java:49) 
    at clojure.lang.RT.seq(RT.java:507) 
    at clojure.core$seq__4128.invoke(core.clj:137) 
    at clojure.core$concat$fn__4215.invoke(core.clj:691) 
    at clojure.lang.LazySeq.sval(LazySeq.java:40) 
    at clojure.lang.LazySeq.seq(LazySeq.java:49) 
    at clojure.lang.RT.seq(RT.java:507) 

........... 
........... 
    at clojure.core$concat$fn__4215.invoke(core.clj:691) 
    at clojure.lang.LazySeq.sval(LazySeq.java:40) 
    at clojure.lang.LazySeq.seq(LazySeq.java:49) 
    at clojure.lang.RT.seq(RT.java:507) 
    at clojure.core$seq__4128.invoke(core.clj:137) 
    at clojure.core$concat$fn__4215.invoke(core.clj:691) 
    at clojure.lang.LazySeq.sval(LazySeq.java:40) 
    at clojure.lang.LazySeq.seq(LazySeq.java:49) 
    at clojure.lang.RT.seq(RT.java:507) 
    at clojure.core$seq__4128.invoke(core.clj:137) 
    at clojure.core$concat$fn__4215.invoke(core.clj:691) 
    at clojure.lang.LazySeq.sval(LazySeq.java:40) 
    at clojure.lang.LazySeq.seq(LazySeq.java:49) 
    at clojure.lang.RT.seq(RT.java:507) 
    at clojure.core$seq__4128.invoke(core.clj:137) 
    at clojure.core$concat$fn__4215.invoke(core.clj:691) 
    at clojure.lang.LazySeq.sval(LazySeq.java:40) 
    at clojure.lang.LazySeq.seq(LazySeq.java:49) 
    at clojure.lang.RT.seq(RT.java:507) 
    at clojure.core$seq__4128.invoke(core.clj:137) 
    at clojure.core$concat$fn__4215.invoke(core.clj:691) 
    at clojure.lang.LazySeq.sval(LazySeq.java:40) 

Antwort

4

core.cache ist eine klassische lazy-Sequenz Fehler zu machen: zusammen viele lazy-Sequenzen verkettet, ohne jemals die Resultate. FIFOCache speichert eine queue of past misses, und wenn es nicht genügend Speicherplatz im Cache hat, entfernt es das älteste Element in der Warteschlange. Anstatt jedoch eine echte Queue-Struktur zu verwenden, verwendet sie eine Lazy-Sequenz und concats zum Ende, mit ähnlichen Ergebnissen wie beispielsweise in Recursive function causing a stack overflow.

Ich würde sagen, das ist ein Fehler in core.cache; Sie können ein Problem gegen its JIRA einreichen oder umgehen, indem Sie nicht so große FIFO-Caches verwenden: Es funktioniert wahrscheinlich bis zu Größen von ein paar tausend oder so.

+0

In Ordnung ... für alle, die an einer Lösung dafür interessiert sind, gibt es hier: https://github.com/ravigit/core.cache. Die Änderungen sind hier: https://github.com/ravigit/core.cache/commit/c8a60dda1d3ff74b7f91eacf97ebcaa1eadb2c30?diff=split. Verwenden Sie sie auf eigene Gefahr! – Ravi

+1

Sie müssen auch 'prune-queue' korrigieren, da sie die Warteschlange durch Aufruf von' remove' in eine Lazy-Sequenz konvertiert. – amalloy

+0

Guter Punkt. Wird bald eine Lösung bereitstellen. – Ravi