可靠地测量JVM分配

我有两个相同的算法的实现。 我想validation他们是否使用了比所需更多的内存,换句话说,他们分配完全相同数量的对象。

我目前的解决方案是通过threadMXBean.getThreadAllocatedBytes(threadId)来测量过程之前和之后分配的字节数,并将其用作内存占用量的近似值。

问题是这个方法是不稳定的,有时它会返回比它应该更多的数字。 它特别显示了不分配对象的算法。 一个有问题的例子是一个总和int[]

实际代码(Kotlin):

 class MemAllocationTest { private val threadMXBean = (ManagementFactory.getThreadMXBean() as? com.sun.management.ThreadMXBean) ?: throw RuntimeException("Runtime does not support com.sun.management.ThreadMXBean") /** * May run [block] several times * */ private inline fun measureAllocatedBytes(block: () -> Unit): Long { val threadId = Thread.currentThread().id val before = threadMXBean.getThreadAllocatedBytes(threadId) block() val after = threadMXBean.getThreadAllocatedBytes(threadId) return after - before } .... 

有更好的解决方案吗?

(我不知道JMH怎么做,但恕我直言,这是一个非常密切的话题)

JMH拥有-prof gc分析器,这对于配置分析来说应该是准确的。 尽管它使用了相同的ThreadMXBean ,但是它可以过滤出热身效果,并且在多个@Benchmark调用中平均打嗝。 典型的错误在0.001字节/ op内。

我目前的解决方案是收集几个运行统计:

 private inline fun stabiliseMeasureAllocatedBytes(block: () -> Unit): Long { val runs = List(7) { measureAllocatedBytes(block) } val results = runs.drop(2) // skip warm-up val counts = results.groupingBy { it }.eachCount() val (commonResult, commonCount) = counts.entries.maxBy { (result, count) -> count }!! if (commonCount >= results.size / 2) return commonResult else throw RuntimeException("Allocation measurements vary too much: $runs") }