我是Clojure的新手,并且没有很多Java经验。
我正在开发一个围绕将一个或多个输入延迟序列转换为新的延迟序列的函数构建的系统。例如,一个函数接受两个序列并在输入之间产生“diff”的延迟序列。
在测试用例中,我在适当的时候验证序列是实现的吗?,但我无法弄清楚如何验证我没有“保持在某个地方”,其他而不是操作一个巨大的序列,并等待OutOfMemoryError。我并不关心这种方法,因为“巨大的序列”是任意的,测试需要很长时间才能运行。
我已经查找了有关Java垃圾收集器的信息,但找不到我要找的东西(或者不理解它)。
建议?
答案 0 :(得分:1)
"正确"监视GC对象资格的方法是使用一些java.lang.ref
引用类型,最好是PhantomReference
,以及ReferenceQueue
。
PhantomReference
与其他java.lang.ref
类的不同之处在于无法用于获取引用的目标;它们只与ReferenceQueue
一起使用。此外,只有在最终确定对象后才能将对象视为幻像。
样板看起来像这样:
(def rq (java.lang.ref.ReferenceQueue.))
(def pref (java.lang.ref.PhantomReference. [1 2] rq))
(future (.remove rq 0) (println :done))
(System/gc)
;;=> :done
最后一行显示了未来的打印输出。
我有一个应该处理样板的小型图书馆,但是唉,它似乎需要一些维护工作......我会尽快尝试并发布它并发布一旦完成就建立一个链接。
答案 1 :(得分:0)
(.totalMemory (Runtime/getRuntime))
将跟踪jvm使用的总内存大小。
检查分配的内存,存储值,在数千个元素序列上运行代码,然后再次检查分配的内存应该得到你想要的。
也许有一种方法可以减少默认大小和分配的粒度,以便检查单元测试中的内存使用量增加。
答案 2 :(得分:0)
一种可能的方法是将WeakReference
存储到seq中,然后在稍后,在对seq的所有引用都应该被丢弃之后的某个时刻,强制进行垃圾收集,通过{{1}取消引用WeakReference并且看到它被清除了。例如:
.get
但是,请注意,在Java中测试与垃圾收集和内存分配相关的任何事情都是一种不精确的科学,因为这些东西是由JVM异步管理的。特别是,(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))))
仅建议 JVM进行垃圾回收;当该方法返回时,无法保证弱引用将被清除,因此该测试会受到虚假故障的影响。出于这个原因,许多风格的检查员会将System.gc()
的呼叫标记为“伏都教”。
一般情况下,只有在显然存在内存泄漏的情况下,才能通过编写可靠代码并在VisualVM等分析器中进行调试来获得最佳效果。