Насколько дорогим является Thread.getStackTrace()?

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

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;
}

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

Ответы

Ответ 1

Да, на этот вызов есть некоторые накладные расходы, но, скорее всего, вы будете делать что-то вроде этого:

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

тогда

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

}

Это приведет к тому, что вы не получите хита в своем реальном коде.

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

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

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

Ответ 2

Похоже, что текущий поток (и связанный с ним ID) не дорог, но получение текущего потока и его трассировки стека. Новый шаблон 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");

Ответ 3

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

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