数组创建与字符串连接哪种日志记录方法性能更好?

2023-12-02

在传递多段字符串进行日志记录时,最好使用可变参数还是字符串连接?

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

考虑下面的代码,

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");

哪一个在两种情况下(启用/禁用)都表现良好?


这些都没有表现得特别好。可变参数会表现得更好,因为它不这样做String连接,这是一个比数组创建更昂贵的操作,但因为您正在使用String可变参数而不是Object可变参数toString()必须在所有对象上调用方法即使在生产中,这会相对昂贵。

不过,不用害怕!这是一个解决了问题. SLF4J(Java 的简单日志外观)已经找到了为您做到这一点的最佳方法。如果您使用 SLF4J 实现(最常见的两个是Log4J and Logback),你可以使用参数化日志参数:

更好的选择

存在一种基于消息格式的便捷替代方案。假设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 中不需要,则存在方法签名,以便不创建数组。 这是完整的文档,您可以在其中看到所有不同的方法签名

如果您决定使用Logback,你应该知道方法调用的成本当日志记录关闭时大约是20纳秒。充分讨论Logback的性能:

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

数组创建与字符串连接哪种日志记录方法性能更好? 的相关文章

随机推荐