Performance Optimization

criterium ((crit/quick-bench (f))), clj-async-profiler (flame graphs), JFR/VisualVM

(set! *warn-on-reflection* true) and add type hints (^String, ^long) Avoid boxed math in hot loops

(set! *unchecked-math*:warn-on-boxed), primitive hints ^long/^double on fn args (up to 4) Transients for batch building

(persistent! (reduce conj! (transient []) xs)) No intermediate collections Choose the right collection

Vectors for indexed access, sets/maps for lookup, java.util collections or arrays for hot mutable loops Avoid laziness overhead where needed

reduce, into, run!, mapv are eager Use records/protocols for hot dispatch Faster than multimethods on hot paths Memoize pure expensive functions memoize, core.memoize (LRU/TTL)

pmap, reducers (r/fold), claypoole, virtual threads Heap size, GC choice (G1/ZGC), AOT compilation for startup time, GraalVM native-image

(require '[criterium.core :as crit])
(crit/quick-bench (reduce + (range 1000000)))

(defn sum-squares ^long [^longs arr]
  (let [n (alength arr)]
    (loop [i 0 acc 0]
      (if (< i n)
        (recur (inc i) (+ acc (* (aget arr i) (aget arr i))))
        acc))))
(sum-squares (long-array (range 1000)))   ; 332833500

(require '[clojure.core.reducers :as r])
(r/fold + (r/map inc (vec (range 1000000))))   ; parallel fold over a vector