Вопрос по java – Трассировка стека NullPointerException недоступна без агента отладки

58

Недавно я обнаружил ошибку, которая вызывает исключение NullPointerException. Исключение перехватывается и регистрируется с использованием стандартного оператора slf4j. Сокращенный код ниже:

for(Action action : actions.getActions()) {
    try {
        context = action.execute(context);
    } catch (Exception e) {
        logger.error("...", e);
        break;
    }
}

Как видите, ничего особенного. Однако из всех имеющихся у нас операторов регистрации исключений только этот не выводит трассировку стека. Все, что он печатает, - это сообщение (представленное как «...») и имя класса исключения (java.lang.NullPointerException).

Так как трассировка стека для исключения загружена лениво, я подумал, что может быть какая-то проблема с переупорядочением команд, и решил вызвать e.getStackTrace () перед оператором log. Это не имеет значения.

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

С тех пор я установил причину исключения. Но я хотел бы узнать, почему трассировка стека была недоступна без отладчика. Кто-нибудь знает

Уточнение: это не проблема ведения журнала. Представьте себе то же самое предложение try / catch, но в подвохе я печатаю значение:

e.getStackTrace().length

Без отладчика это печатает '0', с отладчиком это печатает положительное число (9 в этом случае).

Дополнительная информация: это происходит на JDK 1.6.0_13, 64-битной, amd64, Linux 2.6.9

JDK 1.6.0_13, 64-разрядная в Linux 2.6.9 omerkudat
Что за ВМ вы используете? это поведение звучиточен странно. Michael Wiles
Я уже исправил основную проблему. Я просто хотел бы объяснить это поведение. omerkudat
Попробуйте записать действия, чтобы вы могли понять, какое действие вызывает это David Rabinowitz
Что происходит, когда вы сами «выбрасываете новое NullPointerException ()» внутри попытки? seth

Ваш Ответ

3   ответа
19

что этот код находится во внутреннем цикле? Затем JIT-компилятор может компилировать стек вызовов для этого в собственный код, теряя информацию стека. Затем, когда вы присоединяете отладчик, он отключает JIT, делая информацию снова доступной.

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

Похоже, что это может иногда случаться для других из комментария в исходном коде этого класса в строке 102:

http: //logging.apache.org/log4j/1.2/xref/org/apache/log4j/spi/LocationInfo.htm

Позднее мне удалось подтвердить, что отключение JIT (JAVA_COMPILER = false) приводит к тому, что трассировка полного стека становится доступной всякий раз, когда возникает это исключение. omerkudat
88

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

Для получения дополнительной информации ознакомьтесь со следующими примечаниями к выпуску:

"Компилятор в виртуальной машине сервера теперь обеспечивает правильные обратные трассировки стека для всех" холодных "встроенных исключений. В целях повышения производительности, когда такое исключение выдается несколько раз, метод может быть перекомпилирован. После перекомпиляции компилятор может выбрать более быстрая тактика с использованием предварительно выделенных исключений, которые не обеспечивают трассировку стека. Чтобы полностью отключить использование предварительно выделенных исключений, используйте этот новый флаг: -XX: -OmitStackTraceInFastThrow. "http: //java.sun.com/j2se/1.5.0/relnotes.htm

Это очень интересно, спасибо, что указал на это. omerkudat
У нас снова возникла та же проблема, и мы попробовали этот вариант, и он работал очень хорошо, намного лучше, чем полное отключение JIT. Благодарность omerkudat
Спасибо за указание на это Daniel
0

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

Если вы вызываете setStackTrace с пустым массивом, это приведет к отображению только текста.

 public class Fark {
   public static void main(String[] args) {
       try {
           Fark.throwMe(args.length != 0);

       }
       catch (Exception e) {
           e.printStackTrace();
       }

   }

     public static final void throwMe(boolean arg) throws Exception{
         Exception e = new NullPointerException();
         if (arg) {
           e.setStackTrace(new StackTraceElement[0]);
         }
         throw e;
     }
 }

Скорее ....

% java Fark
java.lang.NullPointerException
        at Fark.throwMe(Fark.java:15)
        at Fark.main(Fark.java:5)

% java Fark nothing
java.lang.NullPointerException
Да, кто-то тоже об этом упоминал. Это не вариант omerkudat
Происходит ли то же самое, если вы сами выбрасываете исключение NullPointerException? seth
Да, такое же поведение, если я сам кидаю вручную. И это происходит только в этом try / catch. В других случаях, когда я выбрасываю вручную, я получаю нормальное (т. Е. Полный стек) поведение. omerkudat

Похожие вопросы