如何断言某些 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 您可以找到有关此主题的更多详细信息。
我有一段代码(目前)使用了 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 您可以找到有关此主题的更多详细信息。