【问题标题】:Clojure - Test to ensure not holding onto head?Clojure - 测试以确保不会抓住头部?
【发布时间】:2013-09-05 18:37:12
【问题描述】:

我是 Clojure 的新手,没有太多 Java 经验。

我正在开发一个系统,该系统是围绕将一个或多个输入惰性序列转换为新的惰性序列的函数构建的。例如,一个函数采用两个序列并产生输入之间“差异”的惰性序列。

在测试用例中,我验证了序列是否在适当的时间实现?,但我不知道如何验证我没有在某个地方“抓住头”,其他而不是对一个巨大的序列进行操作并等待 OutOfMemoryError。我不喜欢这种方法,因为“大序列”是任意的,并且测试需要很长时间才能运行。

我已查找有关 Java 垃圾收集器的信息,但找不到我要查找的内容(或不理解)。

建议?

【问题讨论】:

    标签: testing clojure


    【解决方案1】:

    监控对象的 GC 资格的“正确”方法是使用一些 java.lang.ref 引用类型,最好是 PhantomReferenceReferenceQueue

    PhantomReferences 与其他java.lang.ref 类的不同之处在于它们不能用于获取引用的目标;它们仅与ReferenceQueues 一起使用。此外,对象只有在最终确定后才被视为虚拟可访问。

    样板文件如下所示:

    (def rq (java.lang.ref.ReferenceQueue.))
    (def pref (java.lang.ref.PhantomReference. [1 2] rq))
    (future (.remove rq 0) (println :done))
    (System/gc)
    ;;=> :done
    

    最后一行显示未来的打印输出。

    我有一个应该处理样板的小型库,但是,唉,它似乎需要一些维护工作......我会尽快解决它并在它发布后发布一个链接完成。

    【讨论】:

    • 我不知道 PhatomReference 或 ReferenceQueue。这些很有趣。 (System/gc) 仍然是一个薄弱环节。谢谢!
    【解决方案2】:

    一种可能的方法是将 WeakReference 存储到 seq 中,然后在稍后的某个时间点,在应该丢弃对 seq 的所有引用之后,强制进行垃圾回收,通过 .get 取消引用 Wea​​kReference 并查看它被清除了。例如:

    (let [r (atom nil)
          s (atom nil)]
      (let [x (repeat 1000 1)]
        (reset! r (java.lang.ref.WeakReference. x))
        (reset! s (map (partial * 2) x)))
    
      ;; the lazy seq created by map has not yet been realized.
      (is (false? (realized? @s)))
    
      ;; Request garbage collection.
      (System/gc)
    
      ;; since it's not realized, the result from map still has a reference
      ;; to the head of its input seq.
      (is (false? (nil? (.get @r))))
    
      ;; Realize the seq returned from map.
      (dorun @s)
      (is (realized? @s))
    
      ;; Request garbage collection again.
      (System/gc)
    
      ;; Once the result from map has been realized, it should discard its reference
      ;; to the head of the input seq.
      (is (nil? (.get @r))))
    

    但请注意,在 Java 中测试任何与垃圾收集和内存分配相关的东西都是不精确的科学,因为这些东西是由 JVM 异步管理的。特别是,System.gc()建议 JVM 进行垃圾收集;无法保证当该方法返回时弱引用将被清除,因此该测试可能会出现虚假失败。出于这个原因,许多样式检查器会将对 System.gc() 的调用标记为“巫毒”。

    一般来说,最好的方法是编写可靠的代码,并仅在明显存在内存泄漏时在诸如 VisualVM 之类的分析器中进行调试。

    【讨论】:

    • 这很酷,示例也很棒,但是 (System/gc) 的摇摇欲坠的不承诺令​​人沮丧......
    • 是的,不幸的是,这是你在 Java 中必须使用的最好的东西。从语言设计的角度来看,少指定诸如 GC 行为之类的东西是有意义的,否则您可能会阻止实现进行其他有用的优化。我已经看到应用程序执行诸如在循环中调用 System.gc() 之类的事情,以说明其效果可能不会立即可见。
    【解决方案3】:

    (.totalMemory (Runtime/getRuntime)) 将跟踪 jvm 使用的总内存大小。

    检查分配的内存,存储值,在数千个元素序列上运行代码,然后再次检查分配的内存应该得到你想要的。

    也许有一种方法可以减少默认大小和分配粒度,以检查单元测试中内存使用量的增加。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-17
      相关资源
      最近更新 更多