Насколько дорог Thread.getStackTrace ()? - PullRequest
16 голосов
/ 27 февраля 2010

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

public void debug(String message) {
    Logger logger = Logger.getLogger(getCallingClass());
    logger.debug(message);
}
...
public Class getCallingClass() {
/*
Calls Thread.getStackTrace() and back traces until the class on the stack trace 
!= this.getClass(). 
*/
    return classFound;
}

Насколько это дорого, и может ли оно иметь значительные потери производительности?

Ответы [ 4 ]

8 голосов
/ 16 мая 2012

Похоже, получение текущего потока (и связанного с ним идентификатора) не дорого, но получение текущего потока и его трассировки стека. Новый шаблон throwable (). GetStackTrace () выглядит намного быстрее, чем шаблон трассировки стека потока.

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

Результаты тестов:

Простой цикл занял 2 мс

Получение текущего потока заняло 10 мс

Получение трассировки стека заняло 29564 мс

Получение трассируемой трассировки стека заняло 19910 мс

Код:

int trials = 10_000_000;

    long start = System.currentTimeMillis();

    long a = 1;
    for (int i = 0; i < trials; i += 1) {
        a += 1;
    }

    long duration = System.currentTimeMillis() - start;
    System.out.println("Simple loop took " + duration + " ms");

    start = System.currentTimeMillis();

    a = 1;
    for (int i = 0; i < trials; i += 1) {
        a += 1;
        Thread.currentThread().getId();
    }

    duration = System.currentTimeMillis() - start;
    System.out.println("Getting current thread took " + duration + " ms");

    start = System.currentTimeMillis();

    a = 1;
    for (int i = 0; i < trials; i += 1) {
        a += 1;
        Thread.currentThread().getStackTrace();
    }

    duration = System.currentTimeMillis() - start;
    System.out.println("Getting stack trace took " + duration + " ms");

            start = System.currentTimeMillis();

    a = 1;
    for (int i = 0; i < trials; i += 1) {
        a += 1;
        (new Throwable()).getStackTrace();
    }

    duration = System.currentTimeMillis() - start;
    System.out.println("Getting throwable stack trace took " + duration + " ms");
8 голосов
/ 27 февраля 2010

Да, у этого вызова есть некоторые издержки, но, по всей вероятности, вы собираетесь сделать что-то вроде этого:

public static boolean DEBUG_ON = true; //change this before your production build

тогда

public void debug(String message){
  if(DEBUG_ON){
     //stack code here
  }

}

Что заставит вас не попадать в ваш реальный код.

Даже тогда, за исключениями, вы будете выдавать исключение из целого стека в своей производственной сборке.

Обратите внимание, что если вы используете приличную подсистему ведения журнала, они, вероятно, уже что-то сделают на основе уровня ведения журнала (в нашей системе ведения журнала, в зависимости от уровня, debug () в основном не работает). Log4j и другие по-разному справляются с этим.

Наконец, я бы сказал: не беспокойтесь об этом, пока это не станет реальной проблемой производительности. Преждевременная оптимизация - корень всего зла:)

4 голосов
/ 04 марта 2018

Теперь с JDK 9 и 10 вы можете использовать StalkWalker, который не является дорогим вызовом.

private void invoke006() {
        var stack = StackWalker.getInstance(StackWalker.Option.SHOW_HIDDEN_FRAMES).walk((s) -> s.collect(Collectors.toList()));
        stack.forEach(stackFrame -> {
            if (stackFrame.getMethodName().equals("masterInvoker")) {
                System.err.println("master called !!");
                System.err.println(StackWalker.getInstance().walk((s) -> s.collect(Collectors.toList())).get(0).getMethodName() + ", line: " + StackWalker.getInstance().walk((s) -> s.collect(Collectors.toList())).get(0).getLineNumber());
            }
        });
    }
4 голосов
/ 27 февраля 2010

Насколько я помню, использование Thread.getStackTrace() оказывает определенное влияние - особенно с большими стеками (например, при использовании на стороне сервера или в ситуациях J2EE). Вы можете попробовать Throwable.getStackTrace() для лучшей производительности.

В любом случае, регулярный вызов этих функций (в отличие от исключительной ситуации) повлияет на ваше приложение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...