NullPointerException rastreamento de pilha não disponível sem agente de depuração
-
21-08-2019 - |
Pergunta
Recentemente encontrado um bug que provoca uma NullPointerException. A exceção é detectada e registrada usando uma instrução slf4j padrão. código abreviado abaixo:
for(Action action : actions.getActions()) {
try {
context = action.execute(context);
} catch (Exception e) {
logger.error("...", e);
break;
}
}
Como você pode ver, nada extravagante. No entanto, de todas as declarações de registro a exceção de que nós temos, apenas um presente não imprime um rastreamento de pilha. Tudo o que imprime é a mensagem (representado como "...") e o nome da classe de exceção (Java.lang.NullPointerException).
Uma vez que o rastreamento de pilha em uma exceção é preguiçoso carregado, eu pensei que talvez haja uma instrução reordenação questão de algum tipo e decidiu chamar e.getStackTrace () antes de a declaração de registro. Este não fez diferença.
Então eu decidi reiniciar com o agente de depuração habilitada. No entanto, porque eu mesmo anexado ao processo, notei que agora os rastreamentos de pilha estava imprimindo. Então, claramente, a presença do agente de depuração causado alguma informação de depuração adicional para se tornar disponível.
Eu tenho desde então fixa a causa da exceção. Mas eu gostaria de saber por que o rastreamento de pilha não estava disponível sem um depurador. Alguém sabe?
Esclarecimento: isso não é uma questão de registro . Imagine a mesma cláusula try / catch, mas na captura, eu imprimir o valor de:
e.getStackTrace().length
Sem um depurador este imprime '0', com um depurador que imprime um número positivo (9 neste caso).
Mais informações: isso está acontecendo no JDK 1.6.0_13, 64bit, amd64, linux 2.6.9
Solução
É possível que este código está em um loop interno? Em seguida, em seguida, o compilador JIT pode ser compilar a pilha de chamadas para que este código nativo, perdendo as informações de pilha. Então, quando você anexar o depurador ele desabilita o JIT, tornando a informação disponível novamente.
As outras exceções manuais manter exibir as informações como o JIT não está otimizando.
Parece que às vezes isso pode acontecer para os outros a partir de um comentário neste código-fonte da classe na linha 102:
http: //logging.apache. org / log4j / 1,2 / refex / org / Apache / log4j / SPI / LocationInfo.html
Outras dicas
Com a JVM bandeira XX: -OmitStackTraceInFastThrow você pode desativar a otimização da JVM desempenho para este caso de uso. Se este parâmetro é dado, que desativa a bandeira, o stacktrace estarão disponíveis.
Para mais informações por favor dê uma olhada nas notas após libertação:
"O compilador no servidor VM oferece agora backtraces de pilha corretas para todos 'frio' built-in exceções. Para efeitos de desempenho, quando tal exceção é lançada algumas vezes, o método pode ser recompilados. Depois de recompilação, o compilador . pode escolher um mais rápido tática usando exceções pré-alocados que não fornecem um rastreamento de pilha Para desativar completamente o uso de exceções pré-alocados, use esta nova bandeira: -XX: -OmitStackTraceInFastThrow ". http://java.sun.com/j2se/1.5.0/relnotes.html
Eu posso replicar este, mas parece um pouco estranho que isso estaria acontecendo em seu lugar Acção.
Se você chamar setStackTrace com um conjunto vazio, que vai causar apenas o texto a ser mostrado.
public class Fark {
public static void main(String[] args) {
try {
Fark.throwMe(args.length != 0);
}
catch (Exception e) {
e.printStackTrace();
}
}
public static final void throwMe(boolean arg) throws Exception{
Exception e = new NullPointerException();
if (arg) {
e.setStackTrace(new StackTraceElement[0]);
}
throw e;
}
}
Executá-lo ....
% java Fark
java.lang.NullPointerException
at Fark.throwMe(Fark.java:15)
at Fark.main(Fark.java:5)
% java Fark nothing
java.lang.NullPointerException