Вопрос

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

java.lang.NullPointerException

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

Это было полезно?

Решение

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

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

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

Другие советы

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

LOG.error(exc);

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

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

Через лень или, возможно, просто не думать об этом. К сожалению, это то, что он не ведет себя, как вы ожидаете. API журналиста на самом деле принимает объект как первый аргумент, а не строку, а затем он вызывает ToString () в аргументе. Поэтому вместо того, чтобы получить приятный симпатичный стек, он просто распечатывает то, что в случае с NPE довольно бесполезно.

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

We have seen this same behavior in the past. It turned out that, for some crazy reason, if a NullPointerException occurred at the same place in the code multiple times, after a while using Log.error(String, Throwable) would stop including full stack traces.

Try looking further back in your log. You may find the culprit.

EDIT: this bug sounds relevant, but it was fixed so long ago it's probably not the cause.

Here is an explanation : Hotspot caused exceptions to lose their stack traces in production – and the fix

I've tested it on Mac OS X

  • java version "1.6.0_26"
  • Java(TM) SE Runtime Environment (build 1.6.0_26-b03-383-11A511)
  • Java HotSpot(TM) 64-Bit Server VM (build 20.1-b02-383, mixed mode)

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

For this specific fragment of code, 12288 iterations (+frequency?) seems to be the limit where JVM has decided to use preallocated exception...

exception.toString does not give you the StackTrace, it only returns

a short description of this throwable. The result is the concatenation of:

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

Use exception.printStackTrace instead to output the StackTrace.

Alternate suggestion - if you're using Eclipse, you could set a breakpoint on NullPointerException itself (in the Debug perspective, go to the "Breakpoints" tab and click on the little icon that has a ! in it)

Check both the "caught" and "uncaught" options - now when you trigger the NPE, you'll immediately breakpoint and you can then step through and see how exactly it is handled and why you're not getting a stack trace.

toString() only returns the exception name and the optional message. I would suggest calling

exception.printStackTrace()

to dump the message, or if you need the gory details:

 StackTraceElement[] trace = exception.getStackTrace()

(Your question is still unclear on whether your code is calling printStackTrace() or this is being done by a logging handler.)

Here are some possible explanations about what might be happening:

  • The logger / handler being used has been configured to only output the exception's message string, not a full stack trace.

  • Your application (or some third-party library) is logging the exception using LOG.error(ex); rather than the 2-argument form of (for example) the log4j Logger method.

  • The message is coming from somewhere different to where you think it is; e.g. it is actually coming some third-party library method, or some random stuff left over from earlier attempts to debug.

  • The exception that is being logged has overloaded some methods to obscure the stacktrace. If that is the case, the exception won't be a genuine NullPointerException, but will be some custom subtype of NPE or even some unconnected exception.

I think that the last possible explanation is pretty unlikely, but people do at least contemplate doing this kind of thing to "prevent" reverse engineering. Of course it only really succeeds in making life difficult for honest developers.

When you are using AspectJ in your project, it may happen that some aspect hides its portion of the stack trace. For example, today I had:

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

This stack trace was printed when running the test via Maven's surefire.

On the other hand, when running the test in IntelliJ, a different stack trace was printed:

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)

This will output the Exception, use only to debug you should handle you exceptions better.

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();
    }
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top