StacktraceのないJavaのnullpointerexception
-
18-09-2019 - |
質問
Javaコードキャッチのインスタンスがありました NullPointerException
, 、しかし、私がStacktraceをログにしようとするとき(基本的に呼び出すことになります Throwable.printStackTrace()
)、私が得るのは:
java.lang.NullPointerException
他の誰かがこれに出くわしましたか? 「Java Null Pointer Empty Stack Trace」のグーグルを試してみましたが、このようなものに出くわしませんでした。
解決
おそらく、多くの最適化を実行するHotspot JVM(元々はSun Microsystemsによって、後にOpenJDKの一部であるOracleが購入した)を使用しています。スタックトレースを取り戻すには、オプションを渡す必要があります -XX:-OmitStackTraceInFastThrow
JVMに。
最適化は、例外(通常はnullpointerexception)が初めて発生すると、フルスタックトレースが印刷され、JVMがスタックトレース(またはおそらくコードの場所)を覚えていることです。その例外が十分に頻繁に発生する場合、スタックトレースはもはや印刷されておらず、より良いパフォーマンスを実現し、同一のスタックトレースでログをあふれさせないようにします。
これがホットスポットJVMでどのように実装されているかを確認するには、 そのコピーを手に入れます グローバル変数を検索します OmitStackTraceInFastThrow
. 。前回コードを見たとき(2019年)、それはファイルにありました graphkit.cpp.
他のヒント
コメントで述べたように、log4jを使用しています。私は(不注意に)私が書いた場所を発見しました
LOG.error(exc);
典型的なものの代わりに
LOG.error("Some informative message", e);
怠lazを通して、あるいはそれについて考えていないだけかもしれません。これの残念な部分は、あなたが期待するように振る舞わないということです。 Logger APIは、実際には文字列ではなく最初の引数としてオブジェクトを取得し、その後、引数にtoString()を呼び出します。したがって、素敵なプリティスタックトレースを取得する代わりに、ToStringを印刷するだけです。これは、NPEの場合はかなり役に立たないものです。
おそらくこれはあなたが経験していることですか?
私たちは過去にこの同じ行動を見ました。何らかのクレイジーな理由で、しばらく使用して、コードの同じ場所でnullpointerexceptionが発生した場合、 Log.error(String, Throwable)
フルスタックトレースを含めるのを停止します。
あなたのログをさらに後ろに見てみてください。犯人を見つけるかもしれません。
編集: このバグ 関連するように聞こえますが、ずっと前に修正されていました。おそらく原因ではありません。
これが説明です: ホットスポットにより、例外が生産中にスタックトレースを失うようになりました - そして修正
Mac OS Xでテストしました
- Javaバージョン「1.6.0_26」
- Java(TM)SEランタイム環境(ビルド1.6.0_26-B03-383-11A511)
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
代わりに、スタックトレースを出力します。
代替提案 - Eclipseを使用している場合、NullPointerException自体にブレークポイントを設定できます(デバッグの観点では、「ブレークポイント」タブに移動し、その!中の小さなアイコンをクリックしてください)
「キャッチ」と「猛攻撃」の両方のオプションを確認します。NPEをトリガーすると、すぐにブレークポイントを付けて、それがどのように処理されるか、なぜスタックトレースを取得していないのかを確認できます。
toString()
例外名とオプションのメッセージのみを返します。電話することをお勧めします
exception.printStackTrace()
メッセージをダンプするか、Goryの詳細が必要な場合は次のとおりです。
StackTraceElement[] trace = exception.getStackTrace()
(あなたの質問はあなたのコードが呼び出しているかどうかまだ不明です printStackTrace()
または、これはロギングハンドラーによって行われています。)
何が起こっているのかについてのいくつかの可能な説明があります:
使用されているロガー /ハンドラーは、完全なスタックトレースではなく、例外のメッセージ文字列のみを出力するように構成されています。
アプリケーション(または一部のサードパーティライブラリ)は、例外を記録しています
LOG.error(ex);
(たとえば)log4jロガーメソッドの2 argument形式ではなく。メッセージは、どこかから異なる場所からあなたが思う場所に来ています。たとえば、実際には、サードパーティライブラリの方法、または以前のデバッグの試みから残ったランダムなものが来ています。
記録されている例外は、スタックトレースを曖昧にするためのいくつかの方法を過負荷にしました。その場合、例外は本物のnullpointerexceptionではありませんが、NPEのカスタムサブタイプまたは接続されていない例外でさえあります。
最後の可能な説明はかなりありそうもないと思いますが、人々は少なくともリバースエンジニアリングを「防ぐ」ためにこの種のことをすることを考えています。もちろん、それは本当に正直な開発者にとって人生を困難にすることに成功するだけです。
プロジェクトでAspectJを使用している場合、いくつかのアスペクトがスタックトレースの部分を隠すことが起こる可能性があります。たとえば、今日は次のとおりです。
java.lang.NullPointerException:
at com.company.product.MyTest.test(MyTest.java:37)
このスタックトレースは、MavenのSureFireを介してテストを実行したときに印刷されました。
一方、Intellijでテストを実行すると、別のスタックトレースが印刷されました。
java.lang.NullPointerException
at com.company.product.library.ArgumentChecker.nonNull(ArgumentChecker.java:67)
at ...
at com.company.product.aspects.CheckArgumentsAspect.wrap(CheckArgumentsAspect.java:82)
at ...
at com.company.product.MyTest.test(MyTest.java:37)
これにより、例外が出力され、例外をより適切に処理する必要があるデバッグのみを使用します。
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();
}