可靠地测量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") }