可靠地衡量JVM分配

时间:2017-12-19 16:48:05

标签: performance kotlin jmh

我有两个相同算法的实现。我想验证它们中的非内存使用的内存多于必要的内容,换句话说,它们分配的内容完全相同。

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

问题是这种方法不稳定,e.i。有时它会返回比它应该更多的数字。它特别显示了不分配对象的算法。一个有问题的例子是对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做到这一点,但恕我直言这是一个非常接近的主题)

2 个答案:

答案 0 :(得分:3)

JMH有-prof gc个分析器,它应该是准确的分配分析。虽然它在掩护下使用相同的ThreadMXBean,但它可以过滤掉预热效果,并在多个@Benchmark调用中平均打嗝。那里的典型误差在0.001字节/ op之内。

答案 1 :(得分:0)

我目前的解决方案是收集多次运行的统计数据:

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")
}