59

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

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

ご覧のとおり、派手なものは何もありません。ただし、すべての例外ログ ステートメントのうち、スタック トレースを出力しないのはこの 1 つだけです。出力されるのは、メッセージ ("..." で表される) と例外クラスの名前 (java.lang.NullPointerException) だけです。

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

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

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

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

e.getStackTrace().length

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

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

4

3 に答える 3

90

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

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

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

于 2010-01-15T09:35:07.263 に答える
20

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

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

このクラスのソース コードの 102 行目のコメントから、これが他のユーザーに時々発生する可能性があるようです。

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

于 2009-07-03T15:18:08.497 に答える
0

これを再現できますが、アクションのどこかでこれが発生するのはちょっと奇妙に思えます。

空の配列で 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
于 2009-07-02T20:21:22.687 に答える