确定一行代码中分配的内存量
Determine the amount of memory being allocated in a line of code
我对性能测试比较陌生,正在尝试确定每行代码分配了多少内存。我尝试将 MemoryMXBean 应用于问题,但得到的结果毫无意义。
我在代码行之前拍摄堆使用情况的快照,然后在代码行之后拍摄快照,最后我存储堆使用量增加时的差异 (假设垃圾收集器 运行 如果它减少了); getSnapshot()
方法来自我的测试代码 运行 ,用于重置计数器并打印结果。然而,这个测试告诉我,我们每行分配超过 20 mb,即使在不进行任何分配的行上也是如此。如果我采用中位数而不是平均值,那么我仍然会胡说八道,告诉我我们每行分配 47 MB。
我如何确定在一行代码中分配了多少内存,and/or 我在使用 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);
}
当我禁用线程本地分配缓冲区(命令行参数 -XX:-UseTLAB
)时,我得到了合理的结果 - memBean.getHeapMemoryUsage().getUsed()
调用为结果增加了一些开销,但很容易确定什么这个开销是(在我的例子中是 240 字节)并从数据中减去它。似乎在使用 -XX:+UseTLAB
(默认设置)时,getUsed()
快照仅在分配新缓冲区时发生变化,导致大多数分配似乎使用零字节堆,而少数分配使用几兆字节堆。我还使用 -XX:+UseParallelGC
来减少使用 -XX:+UseG1GC
时的抖动量
我对性能测试比较陌生,正在尝试确定每行代码分配了多少内存。我尝试将 MemoryMXBean 应用于问题,但得到的结果毫无意义。
我在代码行之前拍摄堆使用情况的快照,然后在代码行之后拍摄快照,最后我存储堆使用量增加时的差异 (假设垃圾收集器 运行 如果它减少了); getSnapshot()
方法来自我的测试代码 运行 ,用于重置计数器并打印结果。然而,这个测试告诉我,我们每行分配超过 20 mb,即使在不进行任何分配的行上也是如此。如果我采用中位数而不是平均值,那么我仍然会胡说八道,告诉我我们每行分配 47 MB。
我如何确定在一行代码中分配了多少内存,and/or 我在使用 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);
}
当我禁用线程本地分配缓冲区(命令行参数 -XX:-UseTLAB
)时,我得到了合理的结果 - memBean.getHeapMemoryUsage().getUsed()
调用为结果增加了一些开销,但很容易确定什么这个开销是(在我的例子中是 240 字节)并从数据中减去它。似乎在使用 -XX:+UseTLAB
(默认设置)时,getUsed()
快照仅在分配新缓冲区时发生变化,导致大多数分配似乎使用零字节堆,而少数分配使用几兆字节堆。我还使用 -XX:+UseParallelGC
来减少使用 -XX:+UseG1GC