web-dev-qa-db-ja.com

NullPointerExceptionスタックトレースはデバッグエージェントなしでは使用できません

最近、NullPointerExceptionを引き起こすバグを発見しました。例外は標準のslf4jステートメントを使用してキャッチされ、ログに記録されます。以下の要約コード:

for(Action action : actions.getActions()) {
    try {
        context = action.execute(context);
    } catch (Exception e) {
        logger.error("...", e);
        break;
    }
}

ご覧のとおり、何も豪華ではありません。ただし、すべての例外ログステートメントの中で、これだけではスタックトレースが出力されません。出力されるのは、メッセージ( "..."として表される)と例外クラスの名前(Java.lang.NullPointerException)だけです。

例外のスタックトレースはレイジーロードされるため、おそらく命令の並べ替えの問題があると考え、ログステートメントの前にe.getStackTrace()を呼び出すことにしました。これは違いがありませんでした。

そこで、デバッグエージェントを有効にして再起動することにしました。ただし、プロセスに接続しているため、スタックトレースが出力されていることに気付きました。そのため、デバッグエージェントの存在により、いくつかの追加のデバッグ情報が利用可能になったことは明らかです。

その後、例外の根本的な原因を修正しました。しかし、デバッガがないとスタックトレースが利用できない理由を知りたいのですが。誰か知ってる?

明確化:これはロギングの問題ではありません。同じtry/catch句を想像してください。ただし、catchでは、次の値を出力します。

e.getStackTrace().length

デバッガーがない場合は「0」が出力され、デバッガーがある場合は正の数(この場合は9)が出力されます。

詳細:これは、JDK 1.6.0_13、64ビット、AMD64、Linux 2.6.9で発生しています

58
omerkudat

このコードが内部ループにある可能性はありますか?次に、JITコンパイラがこれの呼び出しスタックをネイティブコードにコンパイルして、スタック情報を失う可能性があります。次に、デバッガーをアタッチすると、JITが無効になり、情報が再び利用可能になります。

JITが最適化していないため、他の手動例外は情報を表示し続けます。

これは、このクラスのソースコードの102行目のコメントから、他の人に起こる可能性があるようです。

http://logging.Apache.org/log4j/1.2/xref/org/Apache/log4j/spi/LocationInfo.html

19
Nick Fortescue

JVMフラグ-XX:-OmitStackTraceInFastThrowを使用すると、このユースケースのJVMのパフォーマンス最適化を無効にできます。このパラメーターを指定すると、フラグが無効になり、スタックトレースが使用可能になります。

詳細については、次のリリースノートをご覧ください。

「サーバーのコンパイラVMは、すべての「コールド」組み込み例外に対して正しいスタックバックトレースを提供するようになりました。パフォーマンスの目的で、そのような例外が数回スローされると、メソッドが再コンパイルされる場合があります。 。再コンパイル後、コンパイラは、スタックトレースを提供しない事前に割り当てられた例外を使用して、より高速な方法を選択できます。事前に割り当てられた例外の使用を完全に無効にするには、次の新しいフラグを使用します:-XX:-OmitStackTraceInFastThrow。 " http:/ /Java.Sun.com/j2se/1.5.0/relnotes.html

89
vesparun

これを再現することはできますが、アクションのどこかでこれが発生するのはちょっと変なようです。

空の配列でsetStackTraceを呼び出すと、テキストのみが表示されます。

 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;
     }
 }

実行しています...

% Java Fark
Java.lang.NullPointerException
        at Fark.throwMe(Fark.Java:15)
        at Fark.main(Fark.Java:5)

% Java Fark nothing
Java.lang.NullPointerException
0
seth