Eu tive instâncias do nosso código Java pegar um NullPointerException
, mas quando tento registrar o StackTrace (que basicamente acaba chamando Throwable.printStackTrace()
), tudo o que recebo é:
java.lang.NullPointerException
Alguém mais se deparou com isso? Tentei pesquisar no Google por "rastreamento de pilha vazia de ponteiro nulo java", mas não encontrei nada parecido com isso.
java
nullpointerexception
Edward Shtern
fonte
fonte
-XX:-OmitStackTraceInFastThrow
dup: stackoverflow.com/questions/4659151/…Respostas:
Você provavelmente está usando o HotSpot JVM (originalmente da Sun Microsystems, posteriormente comprado pela Oracle, parte do OpenJDK), que executa muita otimização. Para recuperar os rastreamentos da pilha, é necessário passar a opção
-XX:-OmitStackTraceInFastThrow
para a JVM.A otimização é que, quando uma exceção (normalmente uma NullPointerException) ocorre pela primeira vez, o rastreamento de pilha completo é impresso e a JVM se lembra do rastreamento de pilha (ou talvez apenas o local do código). Quando essa exceção ocorre com bastante frequência, o rastreamento de pilha não é mais impresso, tanto para obter melhor desempenho quanto para não inundar o log com rastreamentos de pilha idênticos.
Para ver como isso é implementado na JVM do HotSpot, pegue uma cópia dela e procure a variável global
OmitStackTraceInFastThrow
. A última vez que olhei o código (em 2019), estava no arquivo graphKit.cpp .fonte
-XX:-OmitStackTraceInFastThrow
flag. Ainda estou para confirmar se foi por isso que também não consegui imprimir os rastreamentos de pilha (por exemplo, usandoe.printStackTrace
), mas parece altamente provável. Expandi a resposta para refletir essa descoberta.Como você mencionou em um comentário, você está usando log4j. Descobri (inadvertidamente) um lugar onde havia escrito
em vez do típico
por preguiça ou talvez simplesmente não pensando nisso. A parte infeliz disso é que não se comporta como você espera. A API do logger, na verdade, leva Object como o primeiro argumento, não uma sequência - e, em seguida, chama toString () no argumento. Portanto, em vez de obter o belo rastreamento de pilha bonita, ele apenas imprime o toString - que no caso do NPE é bastante inútil.
Talvez seja isso que você está enfrentando?
fonte
Vimos esse mesmo comportamento no passado. Aconteceu que, por algum motivo louco, se uma NullPointerException ocorresse no mesmo local no código várias vezes, depois de um tempo, o uso
Log.error(String, Throwable)
pararia de incluir rastreamentos de pilha completos.Tente olhar mais para trás em seu log. Você pode encontrar o culpado.
EDIT: este bug parece relevante, mas foi corrigido há muito tempo, provavelmente não é a causa.
fonte
-XX:-OmitStackTraceInFastThrow
bandeira da JVM sugerida por Joshua? Consulte também stackoverflow.com/a/2070568/6198 .Aqui está uma explicação: ponto de acesso fez com que as exceções perdessem seus rastreamentos de pilha na produção - e a correção
Eu testei no Mac OS X
VM do servidor Java HotSpot (TM) de 64 bits (compilação 20.1-b02-383, modo misto)
Para esse fragmento específico de código, 12288 iterações (+ frequência?) Parecem ser o limite em que a JVM decidiu usar a exceção pré-alocada ...
fonte
exception.toString
não fornece o StackTrace, ele apenas retornaUse em
exception.printStackTrace
vez disso para gerar o StackTrace.fonte
getStackTrace()
para garantir que o problema não está no seu criador de logs?Sugestão alternativa - se você estiver usando o Eclipse, poderá definir um ponto de interrupção no próprio NullPointerException (na perspectiva Debug, vá para a guia "Pontos de interrupção" e clique no pequeno ícone que possui um!)
Marque as opções "capturadas" e "não capturadas" - agora, quando você acionar o NPE, você imediatamente interromperá o processo e poderá ver como exatamente ele é tratado e por que não está recebendo um rastreamento de pilha.
fonte
toString()
retorna apenas o nome da exceção e a mensagem opcional. Eu sugeriria ligarpara despejar a mensagem ou se você precisar dos detalhes sangrentos:
fonte
(Sua pergunta ainda não está clara se o seu código está chamando
printStackTrace()
ou se está sendo feito por um manipulador de log.)Aqui estão algumas explicações possíveis sobre o que pode estar acontecendo:
O criador de logs / manipulador que está sendo usado foi configurado para emitir apenas a sequência de mensagens da exceção, não um rastreamento de pilha completo.
Seu aplicativo (ou alguma biblioteca de terceiros) está registrando a exceção usando,
LOG.error(ex);
em vez da forma de 2 argumentos (por exemplo), o método log4j Logger.A mensagem vem de um lugar diferente de onde você pensa que é; por exemplo, está realmente chegando a algum método de biblioteca de terceiros ou a algumas coisas aleatórias que sobraram de tentativas anteriores de depuração.
A exceção que está sendo registrada sobrecarregou alguns métodos para ocultar o rastreamento de pilha. Se for esse o caso, a exceção não será uma NullPointerException genuína, mas haverá algum subtipo personalizado do NPE ou mesmo uma exceção não conectada.
Eu acho que a última explicação possível é bastante improvável, mas as pessoas pelo menos consideram fazer esse tipo de coisa para "impedir" a engenharia reversa. Obviamente, ele realmente consegue dificultar a vida de desenvolvedores honestos.
fonte
Quando você está usando o AspectJ em seu projeto, pode ser que algum aspecto oculte sua parte do rastreamento da pilha. Por exemplo, hoje eu tive:
Esse rastreamento de pilha foi impresso ao executar o teste através do Maven.
Por outro lado, ao executar o teste no IntelliJ, um rastreamento de pilha diferente foi impresso:
fonte
Isso produzirá a exceção, use apenas para depurar, você deve lidar melhor com as exceções.
fonte