我有两个相同算法的实现。我想验证它们中的非内存使用的内存多于必要的内容,换句话说,它们分配的内容完全相同。
我目前的解决方案是通过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做到这一点,但恕我直言这是一个非常接近的主题)
答案 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")
}