これまでに見たことのない状態によって引き起こされるハイゼンバグの典型的な例があります。私のレガシー アプリケーション (約 100K sloc の古いコード) が特定のインスタンスで正しく動作せず、JPDA をリモート デバッグに有効にするだけで動作が十分に変化し、アプリケーションが正しく動作するようになります: "-Xdebug -Xnoagent -Xrunjdwp: transport=dt_socket,server=y,suspend=n,address=6666" を vm のコマンド ラインに追加すると、バグが隠されます (実際の接続の有無にかかわらず)。完全に再現可能なテスト ケースがあることを考えると、非表示に戻った場合に備えて、コードを変更して混乱させることはあまりありません。もちろん、これは本番環境でのみ発生しています。
通常、私はすぐにスレッドの問題を想定しますが、a) 100% の動作に対して 100% の動作が失敗し、b) 問題のコード パスでスレッドが明示的に使用されていません。その後、私たちのチームはこの動作の他の理由のリストを作成しようとしていたので、スタック オーバーフローのグループ マインドがさらに追加できるのではないかと考えました。
Java の Heisenbugs:
- スレッド: 不適切な同期、競合状態、暗黙の順序の仮定。
- 明示的なデバッグ/ログ コード: コード パスの変更により、問題が発生/防止されます。それほど頻繁ではありませんが、ログ レベルの変更により、タイミングの変更 (再びスレッド化) や I/O リソースの使用の違いが生じる可能性があります。
- ネイティブ コード ライブラリは、Java 以外の Heisenbug の問題を引きずり込む可能性があります。
- ファイナライザーが予測どおりに実行されることを期待しています。
- 弱参照に関する不適切な仮定。
- 固定サイズのキャッシュがいっぱいになることはないと仮定します。
- ハッシュコードの一意性を期待しています。
- == が文字列で機能する (または、場合によってはインターンされる可能性のある文字列では機能しない) という仮定。
- VM のバグです (いや、そんなことは決してありません;)。
- テスト方法のエラー。特に、テストの成功に依存する隠し変数がある場合。(これは私たちの実際の問題のようです。1 つのテストが成功すると、顧客は次のテストを実行するようになりましたが、ポリシーの問題が原因で失敗しました。失敗すると、ポリシーに従ってデバッグ モードで実行され、結果として成功しました。ため息)
調査する価値のある他のケースはありますか?
編集:
- はい、JPDA 有効化コードは古い構文を使用しています。最新の構文を使用しても動作が変わるかどうかはテストしていません。
- この特定のマシンは、JRE に 1.8.0_45-b14、および HotSpot 64 ビット サーバー VM (ビルド 25.45-b02) を使用しています。
- 質問は一般的であることを意図していますが、扇動する問題は現実的で最新のものです。問題は配備されたシステムで顕在化しているため、回避策として -Xdebug を使用して実行したままにしておくことと、根本的なバグを追跡してそれを強制終了したいことの間で悩んでいます。
- 問題の誤動作しているプログラムは、多段階のデータ処理パイプラインの一部です。詳細は重要ではありませんが、データベースから情報を取得し、それを使用してファイルを変更するスタンドアロン アプリケーションとして理解するのが最適です。破損しているシステムの部分は、データベースからの情報が正しく解釈されていないように見えます。破損したオブジェクトの ORM またはキャッシュからのものです。「壊れた」場合、(db の内容に基づいて) 実行する作業があるかどうかを判断するアプリケーション ロジックは、すべての反復 (プログラムの複数の呼び出しを含む数千回の反復) で間違った選択を行います。「機能している」場合 (唯一の違いは、vm が -Xdebug で実行されているかどうかです)、アプリケーションはすべての反復に対して正しい選択を行います。この構成では完全に一貫しています。異なるデータベースに対して同じコードを実行しても失敗しません。過去に同様の動作が見られたといういくつかの証拠があります (このコードに私が関与する前)