NullPointerException в Java без StackTrace - PullRequest
284 голосов
/ 09 марта 2010

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

java.lang.NullPointerException

Кто-нибудь еще сталкивался с этим? Я пробовал поискать в Google «трассировку пустого стека пустого указателя Java», но ничего подобного не встречал.

Ответы [ 10 ]

333 голосов
/ 10 июня 2010

Вы, вероятно, используете JSM HotSpot (первоначально Sun Microsystems, позже купленную Oracle, часть OpenJDK), которая выполняет большую оптимизацию. Чтобы вернуть трассировку стека, вам нужно передать опцию -XX:-OmitStackTraceInFastThrow в JVM.

Оптимизация заключается в том, что, когда исключение (обычно NullPointerException) возникает впервые, печатается полная трассировка стека, и JVM запоминает трассировку стека (или, возможно, только местоположение кода). Когда это исключение возникает достаточно часто, трассировка стека больше не печатается, чтобы повысить производительность и не заполнять журнал идентичными трассами стека.

Чтобы увидеть, как это реализовано в JVM HotSpot, возьмите его копию и найдите глобальную переменную OmitStackTraceInFastThrow. В прошлый раз, когда я смотрел на код (в 2019 году), он был в файле graphKit.cpp .

56 голосов
/ 09 марта 2010

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

LOG.error(exc);

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

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

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

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

25 голосов
/ 10 марта 2010

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

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

РЕДАКТИРОВАТЬ: эта ошибка звучит актуально, но это было исправлено так давно, что, вероятно, не причина.

19 голосов
/ 15 октября 2011

Вот объяснение: Hotspot вызвал исключения, чтобы потерять их следы стека в производстве - и исправление

Я тестировал его на Mac OS X

  • Java-версия "1.6.0_26"
  • Java (TM) SE Runtime Environment (сборка 1.6.0_26-b03-383-11A511)
  • Java HotSpot (TM) Виртуальная 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 решила использовать предварительно выделенное исключение ...

10 голосов
/ 09 марта 2010

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

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

* 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.

4 голосов
/ 09 марта 2010

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

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

1 голос
/ 07 июня 2017

Когда вы используете 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)
1 голос
/ 10 марта 2010

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

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

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

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

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

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

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

1 голос
/ 09 марта 2010

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

exception.printStackTrace()

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

 StackTraceElement[] trace = exception.getStackTrace()
0 голосов
/ 09 марта 2010

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

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();
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...