如何断言某些 Java 方法是无垃圾的?

How to assert some Java method is garbage free?

我有一段代码(目前)使用了 Java 8 的 Optional 和 Stream。自此代码部署到生产环境后,我们开始遇到 GC 开销问题。请参阅下面代码的要点(为清楚起见,删除了吸气剂、构造函数和重载):

class DynamicFilter extends org.apache.logging.log4j.core.filter.AbstractFilter {

  private Config config;

  @Override
  public Result filter (LogEvent event) {
    Level threshold = config.threshold (event);

    return event.getLevel ().isMoreSpecificThan (threshold) ? onMatch : onMismatch;
  }

}

class Config {

  private Level defaultLevel;

  private List<Overwrite> overwrite;

  public Level threshold (LogEvent log) {
    return overwrites.stream ()
      .filter (o -> o.match (log))
      .findFirst ()
      .map (Overwrite::getThreshold)
      .orElse (defaultLevel);
  }

}

class Overwrite {

  private Level threshold;

  private List<Predicate<LogEvent>> conditions;

  public boolean match (LogEvent log) {
    return conditions.stream ()
      .allMatch (c -> c.test (log));
  }

}

虽然它可能不相关,但我想让这段代码没有垃圾,尤其是因为它是每个日志语句中的代码 运行。使用 for 循环和 if 语句这应该不是很难,但是有没有一种方法可以断言我没有忘记一些讨厌的对象分配?例如。 int 被自动装箱?

TLDR:有没有办法让我编写单元测试,例如:

memory.startRecording ();
myCode.run ();
memory.assertNoCallToNewInCurrentThreadSinceRecordingStarted ();

PS

在生产环境中禁用此代码并未解决 GC 开销问题。我保持这个问题悬而未决,因为我相信能够断言一些代码不做任何分配对未来的读者有用,但我现在不需要它。

JVM 中的每个线程都维护分配计数器,计算自线程创建以来分配的字节数。 您可以使用此计数器来测量一段代码完成的分配量(尽管它应该 运行 在父线程中)。

下面是我通常用于该目的的代码片段。

import java.lang.management.ManagementFactory;

public class MemMeter {

    private static long OFFSET = measure(new Runnable() {
        @Override
        public void run() {
        }
    });

    /**
     * @return amount of memory allocated while executing provided {@link Runnable}
     */
    public static long measure(Runnable x) {
       long now = getCurrentThreadAllocatedBytes();
       x.run();
       long diff = getCurrentThreadAllocatedBytes() - now;
       return diff - OFFSET;
    }

    @SuppressWarnings("restriction")
    private static long getCurrentThreadAllocatedBytes() {
        return ((com.sun.management.ThreadMXBean)ManagementFactory.getThreadMXBean()).getThreadAllocatedBytes(Thread.currentThread().getId());
    }
}

Here 您可以找到有关此主题的更多详细信息。