Вывод журнала неоднозначен! Сращивание символов VS заполнители, какой метод следует использовать?

Java
Вывод журнала неоднозначен! Сращивание символов VS заполнители, какой метод следует использовать?

предисловие

Так совпало, что в эти дни я читаю книгу под названием "Практика оптимизации производительности системы Java", написанную Ли Цзяжи. В главе, посвященной анализу кода, я упомянул проблему с выводом журнала. Давайте посмотрим, как мы изначально выводим информацию. , следующим образом.

private static  Logger logger = LoggerFactory.getLogger(FileManageApplication.class);

public static void main(String[] args) {
	logger.info("日志输出{}",1);
}

Первый параметр — это шаблон формата, «{}» — заполнитель, а второй параметр — тип, который может бытьObject... arguments, то "{}" в первом параметре поочередно заменяется данными этого массива. Если ничего другого, то будет выведена следующая информация.

2021年01月07日 19:52:09:INFO main (FileManageApplication.java:35) - 日志输出1

Однако он не рекомендует использовать этот метод. Причина в том, что процесс замены заполнителя "{}" на целевую переменную внутри среды ведения журнала займет много времени. Учитывая, что метод info может вызываться часто, он повлияет на производительность, поэтому рекомендуется выполнять сплайсинг напрямую, код выглядит следующим образом:

public static void main(String[] args) {
	User user  =getUser();
	logger.info("用户名:"+user.getUserName());
}

Это звучит немного разумно, но сегодня утром я наткнулся на статью на официальном аккаунте, в которой также упоминалась эта проблема (это большая буква V), в которой говорилось: «Не выполняйте сращивание струн, это приведет к Строковые объекты занимают место, влияют на производительность».

what???

И привел контрпример следующим образом:

logger.debug("Processing trade with id: " + id + " symbol: " + symbol);

И есть положительный пример, а именно:

logger.debug("Processing trade with id:[{}] and symbol : [{}] ", id, symbol)

Кроме того, этот формат более удобочитаем и полезен для устранения неполадок.

Итак, какой метод мы используем в конце?

Давайте посмотрим на тест сами.

сравнение времени

Использовать сплайсинг

public class Main {
    private static Logger logger = LoggerFactory.getLogger(Main.class);
    public static void main(String[] args) {
        long startTimer = System.currentTimeMillis();
        for (int i = 0; i < 200000; i++) {
            logger.info("i="+i);
        }
        System.out.println(System.currentTimeMillis()-startTimer);
        
    }
}

Пробежав 10 раз, результаты следующие, средний результат 512,2.

534、510、486、518、495、505、526、507、511、530

Использовать метод шаблона

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {
    private static Logger logger = LoggerFactory.getLogger(Main.class);
    public static void main(String[] args) {
        long startTimer = System.currentTimeMillis();
        for (int i = 0; i < 200000; i++) {
            logger.info("i={}",i);
        }
        System.out.println(System.currentTimeMillis()-startTimer);
    }
}

Пробежав 10 раз, результаты следующие, средний результат 642,9.

654、648、599、624、678、660、643、656、583、684

Ведь, как говорится в книге, процесс замены "{}" занимает много времени.

здесь не используетсяSystem.out.println()Для сравнения, потому что это слишком медленно, потому что внутренняя блокировка задействована.

сравнение использования памяти

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class Main extends JFrame {
    private static Logger logger = LoggerFactory.getLogger(Main.class);

    public Main() {
        this.setSize(300, 300);
        this.setVisible(true);
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);

        JButton jButton = new JButton("开始");
        jButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                for (int i = 0; i < 1000000; i++) {
                    logger.info("i={}",i);
//                    logger.info("i="+ i);
                }
            }
        });
        this.add(jButton);
    }

    public static void main(String[] args) {
        new Main();
    }
}

Метод шаблона

После нажатия кнопки и ожидания завершения вывода память застряла на 112 764 КБ.

После выполнения GC он упал до 13 484 КБ.

Метод сращивания

После нажатия кнопки и ожидания завершения вывода память застряла на 128 014 КБ, разница составляет 15 250 КБ.

После выполнения GC он упал до 17 777 КБ.

В этом сравнении память, занимаемая методом сплайсинга, выше, что также соответствует общедоступной учетной записи.

В заключение

Очевидно, что у каждого есть свои преимущества, поэтому вы можете смотреть только на свои потребности.Кроме того, в исходном коде Tomcat также используется метод сплайсинга....

В Руководстве по разработке Java для Alibaba также сказано....