2017-08-20 1 views
2

Criteriumライブラリを使用して式をベンチマークしようとしています。式は、それは私がOutOfMemoryError:GCオーバーヘッドの上限を超えました。Criterium

(criterium.core/bench (vec (range 10000000))) 

を入力し、私は、これはヒープの最大サイズ(意味hereを見てきたように、しばらくして、私は

OutOfMemoryError GC overhead limit exceeded java.lang.Long.valueOf (Long.java:840) 

を取得し、ベンチマークに

(vec (range 10000000)) 

です1 GB)は、データが収まるだけでは不十分で、ガベージコレクタは空き領域を確保しようとしますが、これを行うことはできません。私はbenchマクロは、デフォルトでは60回の実行を行うことhereを見てきましたので、しかし、以下のような式がちなみに

(dotimes [i 60] (time (vec (range 10000000)))) 

このエラーを生成しませんmicrobenchmarking、私は60回に設定します。

Criteriumを使用しているときにこの問題が発生するのはなぜですか。

編集:

{:max (.maxMemory (Runtime/getRuntime)), :total (.totalMemory (Runtime/getRuntime))} 

出力

{:max 922746880, :total 212860928} 

の下にコードREPL新鮮を開始するとき、私は(dotimes [i 60] (time (vec (range 10000000))))または(criterium.core/bench (vec (range 10000000)))

を実行した後、それは

{:max 922746880, :total 922746880} 
0123を出力
+0

このコードを実行したときのヒープの大きさを知っていれば、回答者はこれを簡単に再現できます。 '{:max(.maxMemory(Runtime/getRuntime))、:total(.totalMemory(Runtime/getRuntime))}'の評価結果はどうですか? – amalloy

+0

@amalloyありがとう、私はそれを含める質問を編集しました。 – Chris

答えて

2

私はこのテストを使用して動作を再現することができました:

;project.clj 
:profiles {:test {:jvm-opts ["-Xms1024m" "-Xmx1024m"]}} 

(:require [clojure.test :refer :all] 
      [criterium.core :as ben]) 

(deftest ^:focused ben-test 
    (is (ben/with-progress-reporting 
     (ben/bench (vec (range 10000000)))))) 

スタックトレースは次のようになります。

Estimating sampling overhead           
Warming up for JIT optimisations 10000000000 ...      
compilation occurred before 377618 iterations      
... 

Estimating execution count ... 
Sampling ... 
Final GC... 
Checking GC... 
Finding outliers ... 
Bootstrapping ... 
Checking outlier significance 
Warming up for JIT optimisations 10000000000 ... 
compilation occurred before 1 iterations 

criterium.core$execute_expr_core_timed_part$fn__40395.invoke (core.clj:370)                                                   
criterium.core$execute_expr_core_timed_part.invokeStatic (core.clj:366)                                                    
criterium.core$execute_expr_core_timed_part.invoke (core.clj:345)                                                     
criterium.core$execute_expr.invokeStatic (core.clj:378)                                                        
criterium.core$execute_expr.invoke (core.clj:374)                                                         
criterium.core$warmup_for_jit.invokeStatic (core.clj:428)                                                       
criterium.core$warmup_for_jit.invoke (core.clj:396)                                                         
criterium.core$run_benchmark.invokeStatic (core.clj:479)                                                       
criterium.core$run_benchmark.invoke (core.clj:470)                                                         
criterium.core$benchmark_STAR_.invokeStatic (core.clj:826)                                                       
criterium.core$benchmark_STAR_.invoke (core.clj:812) 

我々は、エラーがJIT-警告 - で発生することをここで見ることができますアップステップ。興味深い点は、関数execute-expr-core-timed-part(core.clj:345)です。この関数は、式(vec(範囲10000000))をn回実行し、その都度返される値をいわゆる可変箇所に保存します。私の仮説は、ここにメモリリークがあるということです。

(time-body 
    (loop [i (long (dec n)) 
     v (f)] 
==> (set-place mutable-place v**) 
    (if (pos? i) 
    (recur (unchecked-dec i) (f)) 
    v))) 
+0

ありがとうございます。この現象が原因でエラーが発生したようです。私は '(do nil)'の中に式をラップし、それは問題なくベンチマークされました。 – Chris

+0

ただし、注意してください:criteriumは、ヒープオブジェクトに結果を格納します。 JVMは '(f)'の結果を計算した後に常に破棄し、 'f'に副作用がないことを証明できれば、ベンチマークしようとしているコードを最適化できます。 – amalloy

+0

@amalloy私は[this](https://github.com/hugoduncan/criterium/blob/develop/src/criterium/core)に数えていました。clj#L354)を呼び出して 'f 'の呼び出しを最適化しないようにしておきますが、私はもっと良い方法を見つけなければならないことを理解しています – Chris

関連する問題