Miałem instancje naszego kodu Java catch a NullPointerException
, ale kiedy próbuję zalogować StackTrace (który w zasadzie kończy się wywołaniem Throwable.printStackTrace()
), otrzymuję tylko:
java.lang.NullPointerException
Czy ktoś jeszcze to spotkał? Próbowałem google dla „java null wskaźnik pusty stos śledzenia”, ale nie natrafiłem na coś takiego.
java
nullpointerexception
Edward Shtern
źródło
źródło
-XX:-OmitStackTraceInFastThrow
dupie: stackoverflow.com/questions/4659151/…Odpowiedzi:
Prawdopodobnie używasz HotSpot JVM (pierwotnie Sun Sunystems, później kupiony przez Oracle, część OpenJDK), który wykonuje wiele optymalizacji. Aby odzyskać ślady stosu, musisz przekazać opcję
-XX:-OmitStackTraceInFastThrow
do JVM.Optymalizacja polega na tym, że gdy wyjątek (zwykle NullPointerException) pojawia się po raz pierwszy, drukowany jest ślad pełnego stosu, a JVM zapamiętuje ślad stosu (a może po prostu lokalizację kodu). Gdy ten wyjątek występuje wystarczająco często, ślad stosu nie jest już drukowany, zarówno w celu uzyskania lepszej wydajności, jak i nie zalewania dziennika identycznymi śladami stosu.
Aby zobaczyć, jak jest to zaimplementowane w maszynie JVM HotSpot, pobierz jego kopię i wyszukaj zmienną globalną
OmitStackTraceInFastThrow
. Ostatnim razem, gdy patrzyłem na kod (w 2019 r.), Był on w pliku graphKit.cpp .źródło
-XX:-OmitStackTraceInFastThrow
flagę. Muszę jeszcze potwierdzić, czy właśnie dlatego nie udało mi się również wydrukować śladów stosu (np. Przy użyciue.printStackTrace
), ale wydaje się to bardzo prawdopodobne. Rozszerzyłem odpowiedź, aby odzwierciedlić to odkrycie.Jak wspomniałeś w komentarzu, używasz log4j. Odkryłem (mimowolnie) miejsce, w którym napisałem
zamiast typowego
przez lenistwo lub może po prostu o tym nie myśląc. Niefortunne jest to, że nie zachowuje się tak, jak się spodziewasz. Interfejs API programu rejestrującego faktycznie przyjmuje Object jako pierwszy argument, a nie ciąg znaków - a następnie wywołuje metodę argumentString (). Zamiast więc ładnego śladu ładnego stosu, po prostu drukuje toString - co w przypadku NPE jest dość bezużyteczne.
Być może właśnie tego doświadczasz?
źródło
Widzieliśmy to samo zachowanie w przeszłości. Okazało się, że z jakiegoś szalonego powodu, jeśli NullPointerException wystąpił wielokrotnie w tym samym miejscu w kodzie, po pewnym czasie za pomocą
Log.error(String, Throwable)
przestałoby zawierać ślady pełnego stosu.Spróbuj spojrzeć wstecz na swój dziennik. Możesz znaleźć winowajcę.
EDYCJA: ten błąd wydaje się istotny, ale został naprawiony tak dawno temu, prawdopodobnie nie jest to przyczyną.
źródło
-XX:-OmitStackTraceInFastThrow
flagi JVM zasugerowanej przez Jozuego? Zobacz także stackoverflow.com/a/2070568/6198 .Oto wyjaśnienie: Hotspot spowodował, że wyjątki utraciły ślady stosu w produkcji - i poprawkę
Przetestowałem to na Mac OS X.
64-bitowa maszyna wirtualna serwera Java HotSpot ™ (wersja 20.1-b02-383, tryb mieszany)
W przypadku tego konkretnego fragmentu kodu wydaje się, że 12288 iteracji (+ częstotliwość?) Jest limitem, w którym JVM zdecydowało się na użycie wstępnie przydzielonego wyjątku ...
źródło
exception.toString
nie daje ci StackTrace, tylko zwracaexception.printStackTrace
Zamiast tego użyj polecenia OutputTrace.źródło
getStackTrace()
aby upewnić się, że problem nie dotyczy Twojego programu rejestrującego?Alternatywne sugestie - jeśli używasz Eclipse, możesz ustawić punkt przerwania w samym NullPointerException (w perspektywie debugowania przejdź do zakładki „Punkty przerwania” i kliknij małą ikonę z ikoną!)
Sprawdź opcje „złapany” i „nie złapany” - teraz, gdy uruchomisz NPE, natychmiast osiągniesz punkt przerwania, a następnie możesz przejść i zobaczyć, jak dokładnie jest obsługiwany i dlaczego nie otrzymujesz śledzenia stosu.
źródło
toString()
zwraca tylko nazwę wyjątku i opcjonalny komunikat. Sugerowałbym dzwonienieaby zrzucić wiadomość lub jeśli potrzebujesz krwawych szczegółów:
źródło
(Twoje pytanie jest nadal niejasne, czy Twój kod dzwoni,
printStackTrace()
czy jest to wykonywane przez program rejestrujący.)Oto kilka możliwych wyjaśnień na temat tego, co może się dziać:
Używany program rejestrujący / moduł obsługi został skonfigurowany tak, aby wyświetlał tylko ciąg komunikatu wyjątku, a nie śledzenie pełnego stosu.
Twoja aplikacja (lub biblioteka innej firmy) rejestruje wyjątek, używając
LOG.error(ex);
zamiast 2-argumentowej formy (na przykład) metody log4j Logger.Wiadomość przychodzi z innego miejsca niż myślisz; np. nadchodzi jakaś metoda biblioteczna innej firmy lub jakieś przypadkowe rzeczy pozostawione z wcześniejszych prób debugowania.
Rejestrowany wyjątek spowodował przeciążenie niektórych metod zasłaniania stosu śledzenia. W takim przypadku wyjątek nie będzie oryginalnym wyjątkiem NullPointerException, ale będzie niestandardowym podtypem NPE lub nawet niepowiązanym wyjątkiem.
Myślę, że ostatnie możliwe wyjaśnienie jest mało prawdopodobne, ale ludzie przynajmniej zastanawiają się nad zrobieniem tego rodzaju rzeczy, aby „zapobiec” inżynierii odwrotnej. Oczywiście naprawdę udaje się tylko utrudniać życie uczciwym programistom.
źródło
Gdy używasz AspectJ w swoim projekcie, może się zdarzyć, że jakiś aspekt ukrywa swoją część śladu stosu. Na przykład dzisiaj miałem:
Ten ślad stosu został wydrukowany podczas uruchamiania testu przez pewnik Maven.
Z drugiej strony podczas uruchamiania testu w IntelliJ wydrukowano inny ślad stosu:
źródło
Spowoduje to wygenerowanie wyjątku, używaj go tylko do debugowania, powinieneś lepiej obsługiwać wyjątki.
źródło