Log4j中的字符串连接性能

use*_*685 4 java performance logging log4j

我经常听到人们说,这是在日志记录时避免String Concatenation和使用的最佳实践之一{}

我正在查看Log4j代码,以了解他们如何处理此问题,并认为他们正在做类似的事情。

这是format()方法的代码片段,其中包含模式和参数,并返回要记录的消息。

/**
 * Formats arguments using SLF4J-like formatter.
 * @param pattern pattern, may be malformed.
 * @param arguments arguments.
 * @return Message string
 */
private static String format(final String pattern,
                             final Object[] arguments) {
    if (pattern != null) {
        String retval = "";
        int count = 0;
        int prev = 0;
        int pos = pattern.indexOf("{");
        while(pos >= 0) {
            if (pos == 0 || pattern.charAt(pos-1) != '\\') {
                retval += pattern.substring(prev, pos);
                if (pos + 1 < pattern.length() && pattern.charAt(pos+1) == '}') {
                    if(arguments != null && count < arguments.length) {
                        retval += arguments[count++];
                    } else {
                        retval += "{}";
                    }
                    prev = pos + 2;
                } else {
                    retval += "{";
                    prev = pos + 1;
                }
            } else {
                retval += pattern.substring(prev, pos - 1) + "{";
                prev = pos + 1;
            }
            pos = pattern.indexOf("{", prev);
        }
        return retval + pattern.substring(prev);
    }
    return null;
}
Run Code Online (Sandbox Code Playgroud)

我不明白这种实现比使用串联更好。任何对此的见解将非常有帮助。

lar*_*fer 6

在日志记录系统中格式化字符串的好处是,日志记录系统可以决定是否必须进行字符串连接。

让我们以这些行为例:

log.debug("Count: " + list.size());
log.debug("Count: {}", list.size());
Run Code Online (Sandbox Code Playgroud)

只要此记录器的级别为debug或更低,性能就没有区别,但是,如果日志级别高于debug,则第二行根本不会执行串联。


Ste*_*n C 5

该问题的一些答案说明:

简短的版本是基于格式的用法更快,因为

   Logger.debug("my name is {}", name);
Run Code Online (Sandbox Code Playgroud)

log4j决定需要记录该事件之后,才进行昂贵的字符串重击;例如,在根据日志记录级别进行过滤之后,等等。

相比之下,使用字符串串联版本

   Logger.debug("my name is " + name);
Run Code Online (Sandbox Code Playgroud)

计算参数时会发生字符串重击。因此,即使在没有实际记录任何事件的情况下,它也会发生。(您可以在代码中使用保护措施来部分避免这种情况,但这会使日志记录代码变得冗长。)


但是看看这个例子:

   log.debug("Count: " + list.size());
   log.debug("Count: {}", list.size());
Run Code Online (Sandbox Code Playgroud)

格式版本会更快,但是两个版本始终会评估list.size()表达式。如果那是一个昂贵的手术,那么您可能需要求助于使用警卫。例如

   if (log.isDebugEnabled()) {
       log.debug("Count: " + list.size());
   }
Run Code Online (Sandbox Code Playgroud)