2010-03-09 4 views
227

У меня были случаи нашего кода Java поймать NullPointerException, но когда я пытаюсь войти в StackTrace (который в основном заканчивается до вызова Throwable.printStackTrace()), все это я получаю:NullPointerException в Java, без StackTrace

java.lang.NullPointerException 

Кто-нибудь еще сталкивался с этим? Я попробовал googling для «java null pointer empty stack trace», но не нашел ничего подобного.

+0

Что такое контекст? Существуют ли несколько потоков? У меня были проблемы с попыткой получить трассировку стека исключения в SwingWorker. –

+0

Здесь нет нитей, просто старая Java. –

+0

попробовал отладчик? – Bozho

ответ

264

Возможно, вы используете Sun JVM, который выполняет большую оптимизацию. Чтобы вернуть трассировку стека, вам необходимо передать опцию -XX:-OmitStackTraceInFastThrow в JVM.

+1

Спасибо за подсказку. Любая идея, если есть какие-то скрытые gotchas для передачи этой опции (кажется довольно безобидной, если мое приложение не бросает тонну исключений)? –

+0

Нет никаких скрытых ошибок, о которых я знаю. Когда вы смотрите исходный код Hotspot, вы можете видеть, что этот параметр используется только в одном месте (graphKit.cpp). И это выглядит хорошо для меня. –

+27

Думал, что я добавлю дополнительный бит информации, который, когда трассировка стека будет оптимизирована, это потому, что он получил полную обработку хотя бы один раз: http://jawspeak.com/2010/05/26/hotspot-caused-exceptions -в-потерять-их стек-следы-в-производства-и-затруднительного / – sharakan

9

exception.toString не дает вам StackTrace, он возвращает только

краткое описание этого Throwable. Результатом является конкатенация:

* the name of the class of this object 
* ": " (a colon and a space) 
* the result of invoking this object's getLocalizedMessage() method 

exception.printStackTrace Используйте вместо того, чтобы выводить StackTrace.

+0

Извините, я ошибся в своем оригинальном посте. Я регистрирую их через Log4J, который использует printStackTrace(). –

+1

Вы пытались использовать 'getStackTrace()', чтобы убедиться, что проблема не с вашим регистратором? –

+1

Если вы используете log4j, обязательно отправьте исключение как часть аргумента методу журнала. Я отправлю ответ с этим. –

1

toString() возвращает только имя исключения и необязательное сообщение. Я хотел бы предложить вызов

exception.printStackTrace() 

сбросить сообщение, или если вам нужна окровавленные детали:

StackTraceElement[] trace = exception.getStackTrace() 
+0

См. Выше - я ошибся - я использую printStackTrace(). –

0

Это выведет Exception, использовать только для отладки, вы должны обрабатывать вам исключение лучше.

import java.io.PrintWriter; 
import java.io.StringWriter; 
    public static String getStackTrace(Throwable t) 
    { 
     StringWriter sw = new StringWriter(); 
     PrintWriter pw = new PrintWriter(sw, true); 
     t.printStackTrace(pw); 
     pw.flush(); 
     sw.flush(); 
     return sw.toString(); 
    } 
48

Как вы упомянули в комментарии, вы используете log4j. Я обнаружил (неумышленно) место, где я написал

LOG.error(exc); 

вместо типичного

LOG.error("Some informative message", e); 

через лени или, возможно, просто не задумываясь об этом. Несчастная часть этого заключается в том, что она не ведет себя так, как вы ожидаете. API-логик фактически принимает Object как первый аргумент, а не строку, а затем вызывает аргумент toString(). Таким образом, вместо того, чтобы получать красивую трассировку стека, она просто печатает toString, что в случае NPE довольно бесполезно.

Возможно, это то, что вы испытываете?

+0

+1: Это объясняет описанное поведение, и вы не единственный, кто это обнаружил :) –

+2

На самом деле у нас есть стандартная политика никогда не использовать первую форму выше (LOG.error (exc);) - мы всегда используем 2, так что мы добавляем некоторые описательные выражения в журналы, а не только из rawtattrace. –

+4

Конечно, но политика не означает, что она всегда выполняется правильно! Понятно, что стоит упомянуть, по крайней мере. –

4

Альтернативное предложение - если вы используете Eclipse, вы можете установить точку останова на самом NullPointerException (! В перспективе отладки, перейдите на вкладку «Breakpoints» и нажмите на иконку, которая имеет в нем)

Проверьте оба параметра «пойман» и «неперехваченные» - теперь, когда вы запускаете NPE, вы сразу же оставите точку останова, и затем вы сможете перейти к ней и посмотреть, как именно она обрабатывается, и почему вы не получаете трассировку стека.

1

(Ваш вопрос по-прежнему неясен о том, звонит ли ваш код printStackTrace(), или это выполняется обработчиком ведения журнала.)

Вот некоторые из возможных объяснений по поводу того, что может происходить:

  • Регистратор/обработчик используется настроены для вывода только строки сообщения, за исключением, а не полные трассировки стеки.

  • Ваше приложение (или какая-либо сторонняя библиотека) регистрирует исключение, используя LOG.error(ex);, а не форму 2-аргумента (например) метода log4j Logger.

  • Сообщение идет откуда-то по-другому, где вы думаете; например на самом деле это приносит некоторый сторонний метод библиотеки или некоторые случайные вещи, оставшиеся от предыдущих попыток отладки.

  • Исключение, которое регистрируется, перегрузило некоторые методы, чтобы скрыть стек. Если это так, исключение не будет подлинным исключением NullPointerException, но будет каким-то обычным подтипом NPE или даже каким-то несвязанным исключением.

Я думаю, что последнее возможное объяснение маловероятно, но люди, по крайней мере, думают, что делают такие вещи, чтобы «предотвратить» обратную инженерию. Конечно, это действительно удастся сделать жизнь трудной для честных разработчиков.

20

Мы видели такое же поведение в прошлом. Оказалось, что по какой-то сумасшедшей причине, если NullPointerException произошло в одном месте в коде несколько раз, через некоторое время использование Log.error(String, Throwable) прекратит включать полные стеки стека.

Попробуйте еще раз вернуться в свой журнал. Вы можете найти виновника.

EDIT:this bug звучит актуально, но это было исправлено так давно, вероятно, это не причина.

+1

Ошибка была закрыта, но флаг -XX: -OmitStackTraceInFastThrow по-прежнему необходим, чтобы обойти оптимизацию производительности. –

+0

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

+2

Pawel, вы пробовали флаг JXM -XX: -OmitStackTraceInFastThrow?, Предложенный Джошуа? См. Также http://stackoverflow.com/a/2070568/6198. –

13

Вот объяснение: Hotspot caused exceptions to lose their stack traces in production – and the fix

Я проверил это на Mac OS X

  • ява версия "1.6.0_26"
  • Java (TM) SE Runtime Environment (сборка 1.6. 0_26-b03-383-11A511)
  • Java HotSpot (ТМ) 64-разрядный сервер ВМ (сборка 20.1-b02-383, смешанный режим)

    Object string = "abcd"; 
    int i = 0; 
    while (i < 12289) { 
        i++; 
        try { 
         Integer a = (Integer) string; 
        } catch (Exception e) { 
         e.printStackTrace(); 
        } 
    } 
    

Для этого конкретного фрагмента кода, 12288 итераций (+ частота?), Кажется, предел, где JVM решил использовать предопределенное исключение ...

0

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

java.lang.NullPointerException: 
    at com.company.product.MyTest.test(MyTest.java:37) 

Эта трассировка стека была напечатана при выполнении теста через верный огонь Maven.

С другой стороны, при выполнении теста в IntelliJ, другой трассировки стека была напечатана:

java.lang.NullPointerException 
    at com.company.product.library.ArgumentChecker.nonNull(ArgumentChecker.java:67) 
    at ... 
    at com.company.product.aspects.CheckArgumentsAspect.wrap(CheckArgumentsAspect.java:82) 
    at ... 
    at com.company.product.MyTest.test(MyTest.java:37) 
Смежные вопросы