对于日志记录方法,哪个数组创建与字符串连接具有更好的性能?

时间:2015-07-31 13:44:11

标签: java performance logging

在传递多个字符串进行日志记录时,最好是使用varargs还是字符串连接?

生产环境中将禁用日志记录。

考虑以下代码,

public void log(int logLevel, String ... msg) {
    if (logLevel >= currentLogLevel) {
        for (String m : msg) {
            // print the log to file
        }
    }
}
// calling
log(2, "text1", var1, "text2");

Vs以上。

public void log(int logLevel, String msg) {
    if (logLevel >= currentLogLevel) {
        // print the log to file
    }
}
// calling
log(2, "text1" + var1 + "text2");

哪一个在两种情况下都有效(启用/禁用)?

3 个答案:

答案 0 :(得分:7)

其中任何一项都表现不佳。 varargs会表现得更好,因为它没有进行String连接,这是一个比数组创建更昂贵的操作,但是因为你使用String varargs而不是Object varargs,toString()方法必须在即使在生产的所有对象上调用,这将相对昂贵。

然而,不要害怕!这是已解决的问题SLF4J (Simple Logging Facade for Java)已经找到了最适合你的方法。如果您使用SLF4J实现(最常见的两个是Log4JLogback),则可以使用parameterized logging arguments

  

更好的选择

     

基于消息格式存在一种方便的替代方案。假设entry是一个对象,你可以写:

Object entry = new SomeObject(); 
logger.debug("The entry is {}.", entry);
     

只有在评估是否记录后,并且只有在决定是肯定的情况下,记录器实现才会格式化消息并替换' {}'与条目的字符串值配对。换句话说,当禁用日志语句时,此表单不会产生参数构造的成本。

     

以下两行将产生完全相同的输出。但是,如果禁用日志记录语句,则第二个变体将比第一个变体的性能优于至少30个。

logger.debug("The new entry is "+entry+".");
logger.debug("The new entry is {}.", entry);
     

也可以使用两个参数变体。例如,您可以写:

logger.debug("The new entry is {}. It replaces {}.", entry, oldEntry);
     

如果需要传递三个或更多参数,则还可以使用Object []变体。例如,您可以写:

Object[] paramArray = {newVal, below, above};
logger.debug("Value {} was inserted between {} and {}.", paramArray);

请注意,在第一种和第二种情况下,它不会创建临时数组,如果在SLF4J中不需要,则方法签名不存在创建数组。 { {3}}

如果您决定使用Logback,您应该知道关闭日志时的方法调用的成本约为20纳秒。 Here is the full documentation where you can see all the different method signatures

  

您可以通过将根记录程序的级别设置为Level.OFF(最高级别)来完全关闭日志记录。完全关闭日志记录时,日志请求的成本包括方法调用和整数比较。在3.2Ghz Pentium D机器上,此成本通常约为20纳秒。

答案 1 :(得分:1)

从Java-8开始,使用%JAVA_HOME%\jre\lib\security\cacerts的替代方案更快:

Supplier<String>

这比串联快得多,前提是你多次执行此行(第一次因为应该创建匿名类而慢)。来源:AlekseyShipilëvtalk on Joker'14(PDF,查看幻灯片26-28)。

答案 2 :(得分:0)

如果您使用SLF4J之类的内容,则可以执行参数化日志消息。喜欢这个

log.info("Item {} is done, it took {} ms", item.getName(), duration);

这也有好处,不必在日志级别检查if(log.isDebugEnabled())中包含其中一些。见this faq