Насколько дорогим является 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()
для лучшей производительности.
Во всяком случае, вызов этих функций регулярно (в отличие от этого в ситуации исключения) повлияет на ваше приложение.