我对性能测试比较陌生,我正在尝试确定每行代码分配的内存量。我尝试将MemoryMXBean应用于问题,但我得到了无意义的结果。
我在代码行之前拍摄堆使用情况的快照,然后我在代码行之后拍摄快照,最后如果堆使用量增加,我将存储差异(假设垃圾收集器运行,如果它减少了); getSnapshot()
方法从我的测试代码运行,用于重置计数器并打印结果。但是,这个测试告诉我,即使在没有进行任何分配的线路上,我们每条线路的分配也超过20 mb。如果我取中位数而不是平均数,那么我仍然无意义地告诉我,我们每行分配47 mb。
如何确定在一行代码中分配了多少内存,和/或我使用MemoryMXBean
时出错了什么?
private static final MemoryMXBean memBean = ManagementFactory.getMemoryMXBean();
private static final Map<Line, Tuple> lineMap;
static {
Map<Line, Tuple> map = new EnumMap<Line, Tuple>(Line.class);
for(Line line : Line.values()) {
map.put(line, new Tuple());
}
lineMap = map;
}
public enum Line {
line01,
line02,
line03,
...
}
public static Map<String, Long> getSnapshot() {
Map<String, Long> returnVal = new HashMap<>();
for(Map.Entry<Line, Tuple> entry : lineMap.entrySet()) {
if(entry.getValue().count.get() > 0) {
returnVal.put(entry.getKey().toString(), entry.getValue().memory.getAndSet(0) / entry.getValue().count.getAndSet(0));
} else {
entry.getValue().memory.set(0);
}
}
return returnVal;
}
private static class Tuple {
public final AtomicLong memory = new AtomicLong();
public final AtomicLong count = new AtomicLong();
}
private static void update(Line line, long value) {
long finish = memBean.getHeapMemoryUsage().getUsed();
// ignore if the gc ran
if(finish > value) {
Tuple tuple = lineMap.get(line);
tuple.memory.addAndGet(finish - value);
tuple.count.incrementAndGet();
}
}
public void codeIamTesting {
long start = memBean.getHeapMemoryUsage().getUsed();
// line1
update(Line.line01, start);
}
答案 0 :(得分:0)
当我禁用线程局部分配缓冲区(命令行参数-XX:-UseTLAB
)时,我得到了理智的结果 - memBean.getHeapMemoryUsage().getUsed()
调用为结果增加了一些开销,但是很容易确定这个开销是多少是(在我的情况下是240字节)并从数据中减去它。看来,当使用-XX:+UseTLAB
(这是默认值)时,getUsed()
快照仅在分配新缓冲区时发生更改,导致大多数分配似乎使用零字节堆,而少数分配使用几兆字节堆。我还使用了-XX:+UseParallelGC
来减少-XX:+UseG1GC