JavaコードのインスタンスがをキャッチしましたNullPointerException
が、StackTrace(基本的には呼び出すことThrowable.printStackTrace()
になります)をログに記録しようとすると、次のようになります。
java.lang.NullPointerException
他の誰かがこれに出くわしましたか?「javanullポインタの空のスタックトレース」をグーグルで検索しようとしましたが、このようなものは見つかりませんでした。
JavaコードのインスタンスがをキャッチしましたNullPointerException
が、StackTrace(基本的には呼び出すことThrowable.printStackTrace()
になります)をログに記録しようとすると、次のようになります。
java.lang.NullPointerException
他の誰かがこれに出くわしましたか?「javanullポインタの空のスタックトレース」をグーグルで検索しようとしましたが、このようなものは見つかりませんでした。
おそらく、多くの最適化を実行する HotSpot JVM (当初は Sun Microsystems、後に Oracle が買収、OpenJDK の一部) を使用しているでしょう。-XX:-OmitStackTraceInFastThrow
スタック トレースを取得するには、オプションを JVMに渡す必要があります。
最適化は、例外 (通常は NullPointerException) が初めて発生したときに、完全なスタック トレースが出力され、JVM がスタック トレース (またはコードの場所のみ) を記憶することです。その例外が頻繁に発生すると、スタック トレースは出力されなくなります。これにより、パフォーマンスが向上し、ログが同一のスタック トレースであふれないようになります。
これが HotSpot JVM でどのように実装されているかを確認するには、そのコピーを取得してグローバル変数を検索しますOmitStackTraceInFastThrow
。前回 (2019 年に) コードを見たとき、それはファイルgraphKit.cppにありました。
コメントで述べたように、log4j を使用しています。書いた場所を (うっかり) 見つけてしまった
LOG.error(exc);
典型的な代わりに
LOG.error("Some informative message", e);
怠惰によって、またはおそらくそれについて考えていないだけです。これの残念な部分は、期待どおりに動作しないことです。ロガー API は、実際には文字列ではなく Object を最初の引数として取り、引数に対して toString() を呼び出します。したがって、きれいなスタック トレースを取得する代わりに、toString を出力するだけです。これは、NPE の場合はほとんど役に立ちません。
おそらくこれはあなたが経験していることですか?
これと同じ動作が過去に見られました。Log.error(String, Throwable)
なんらかの理由で、NullPointerException がコードの同じ場所で複数回発生した場合、しばらくすると完全なスタック トレースが含まれなくなることが判明しました。
ログをさらに遡ってみてください。犯人が見つかるかもしれません。
編集: このバグは関連しているように聞こえますが、かなり前に修正されたため、おそらく原因ではありません。
説明は次のとおりです: Hotspot により例外が発生し、本番環境でスタック トレースが失われました – および修正
Mac OS Xでテストしました
Java HotSpot(TM) 64 ビット サーバー VM (ビルド 20.1-b02-383、混合モード)
Object string = "abcd";
int i = 0;
while (i < 12289) {
i++;
try {
Integer a = (Integer) string;
} catch (Exception e) {
e.printStackTrace();
}
}
このコードの特定の断片では、12288回の繰り返し(+頻度?)が、JVMが事前割り当て例外の使用を決定した制限のようです...
exception.toString
StackTrace は提供されず、返されるだけです
このスロー可能なオブジェクトの簡単な説明。結果は次の連結です。
* the name of the class of this object * ": " (a colon and a space) * the result of invoking this object's getLocalizedMessage() method
代わりに使用exception.printStackTrace
して、StackTrace を出力します。
別の提案 - Eclipse を使用している場合は、NullPointerException 自体にブレークポイントを設定できます ([デバッグ] パースペクティブで [ブレークポイント] タブに移動し、! が含まれる小さなアイコンをクリックします)。
「キャッチ」オプションと「キャッチされていない」オプションの両方を確認してください。NPE をトリガーするとすぐにブレークポイントが表示され、ステップスルーして、それがどのように正確に処理され、スタック トレースが得られないのかを確認できます。
toString()
例外名とオプションのメッセージのみを返します。電話することをお勧めします
exception.printStackTrace()
メッセージをダンプする場合、または悲惨な詳細が必要な場合:
StackTraceElement[] trace = exception.getStackTrace()
これは例外を出力します。デバッグにのみ使用して、例外をより適切に処理する必要があります。
import java.io.PrintWriter;
import java.io.StringWriter;
public static String getStackTrace(Throwable t)
{
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw, true);
t.printStackTrace(pw);
pw.flush();
sw.flush();
return sw.toString();
}
(あなたのコードが呼び出しているのか、それともprintStackTrace()
ロギング ハンドラによって行われているのか、あなたの質問はまだ不明です。)
何が起こっているのかについて、いくつかの可能な説明を次に示します。
使用されているロガー/ハンドラーは、完全なスタック トレースではなく、例外のメッセージ文字列のみを出力するように構成されています。
アプリケーション (または一部のサードパーティ ライブラリ) はLOG.error(ex);
、(たとえば) log4j Logger メソッドの 2 引数形式ではなく、例外をログに記録しています。
メッセージは、あなたが思っている場所とは別の場所から来ています。たとえば、実際には、サードパーティのライブラリ メソッドや、以前のデバッグの試みから残ったランダムなものが来ています。
ログに記録されている例外は、いくつかのメソッドをオーバーロードして、スタック トレースを覆い隠しています。その場合、例外は本物の NullPointerException ではなく、NPE のカスタム サブタイプまたは接続されていない例外になります。
最後の可能な説明はかなりありそうにないと思いますが、リバースエンジニアリングを「防ぐ」ためにこの種のことを行うことを少なくとも考えている人はいます。もちろん、正直な開発者の生活を困難にするだけです。