Clojure OutOfMemoryError:GC开销限制超出标准

Clojure OutOfMemoryError:GC开销限制超出标准,clojure,out-of-memory,benchmarking,Clojure,Out Of Memory,Benchmarking,我正在尝试使用库对表达式进行基准测试。表达式是 (vec (range 10000000)) 要对其进行基准测试,我需要键入 (criterium.core/bench (vec (range 10000000))) 过了一段时间,我就明白了 OutOfMemoryError GC overhead limit exceeded java.lang.Long.valueOf (Long.java:840) 正如我所看到的,这意味着堆的最大大小(1GB)不足以容纳数据,垃圾收集器试图释

我正在尝试使用库对表达式进行基准测试。表达式是

(vec (range 10000000))
要对其进行基准测试,我需要键入

 (criterium.core/bench (vec (range 10000000)))
过了一段时间,我就明白了

 OutOfMemoryError GC overhead limit exceeded  java.lang.Long.valueOf (Long.java:840)
正如我所看到的,这意味着堆的最大大小(1GB)不足以容纳数据,垃圾收集器试图释放空间,但无法做到这一点。然而,像下面这样对表达式进行微基准标记不会产生此错误

(dotimes [i 60] (time (vec (range 10000000))))
顺便说一下,我将其设置为60次,因为我已经看到
bench
宏默认执行60次

问题是为什么在使用Criteriam时会发生这种情况

编辑:启动新的repl时,请输入以下代码

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

{:max 922746880, :total 212860928}
运行
(dotimes[i 60](时间(vec(范围10000000)))
(criterium.core/bench(vec(范围10000000)))

它输出

{:max 922746880, :total 922746880}

我能够通过这个测试重现这种行为:

;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警告步骤中。有趣的一点是函数executeexprcoretimedpart(core.clj:345)。此函数执行表达式(vec(range 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)))

如果回答者知道您运行此代码时的堆有多大,他们将更容易重现。计算
{:max(.maxMemory(Runtime/getRuntime)),:total(.totalMemory(Runtime/getRuntime))}
的结果是什么?@amalloy谢谢,我已经编辑了这个问题,将其包括在内。谢谢,因为似乎是这个行为导致了错误。我将表达式包装在一个
(do nil)
中,并对其进行了基准测试,没有任何问题。但要小心:criterium将其结果存储在heap对象中是有原因的。JVM可能会观察到,您总是在计算后丢弃
(f)
的结果,如果它能证明
f
没有副作用,它可能会优化您尝试基准测试的代码。@amalloy我指望对“f”的调用保持未优化状态,但我知道我必须找到更好的方法。您链接到的注释解释了函数的要点是强制对
f
的调用不优化。这是通过保存结果来实现的。通过将
f
中的结果扔掉,您可以移除这种保护:优化器现在可以在优化
f
本身时,决定将其编译为禁止操作。这通常是好的,因为JVM通常不会注意到,根据我的经验,它可以优化这些内容。但我的观点是,如果你避开它的特点,你就不能指望它的评论。