确定一行代码中分配的内存量

时间:2016-06-05 14:16:37

标签: java memory memory-management performance-testing jmx

我对性能测试比较陌生,我正在尝试确定每行代码分配的内存量。我尝试将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);
}

1 个答案:

答案 0 :(得分:0)

当我禁用线程局部分配缓冲区(命令行参数-XX:-UseTLAB)时,我得到了理智的结果 - memBean.getHeapMemoryUsage().getUsed()调用为结果增加了一些开销,但是很容易确定这个开销是多少是(在我的情况下是240字节)并从数据中减去它。看来,当使用-XX:+UseTLAB(这是默认值)时,getUsed()快照仅在分配新缓冲区时发生更改,导致大多数分配似乎使用零字节堆,而少数分配使用几兆字节堆。我还使用了-XX:+UseParallelGC来减少-XX:+UseG1GC

所带来的抖动量