9

try {} catch {}ブロック トレースとスタック トレースがどのように機能するかについて知りたいと思います。

例外処理のアンチパターンに関するこのすばらしい記事を読んでいて、次の段落を見つけました。

catch (NoSuchMethodException e) {
  throw new MyServiceException("Blah: " +
      e.getMessage());
}

これは元の例外のスタック トレースを破棄し、常に間違っています。

その後、私は自分がどのように機能するのかよくわからないtry/catchことに気づきました。私の理解は次のとおりです。例を考えてみましょう:

void top() {
    try {
        f();
    } catch (MyException ex) {
        handleIt(); 
    } finally {
        cleanup();
    }
}

void f() {
    g();
}

void g() {
    throw new MyException();
}

を呼び出すtop()と、コール チェーン はコール スタックにtop -> f -> g 2 つのスタック フレームを残します (topおよびf関数用)。で例外が発生すると、プログラムは例外を処理するブロックがg見つかるまで実行スタックをバブルアップします。try/catchその間、スタックフレームを解放し、スタックトレース情報を渡してcatchスタックトレースを出力できる「魔法の」オブジェクトに添付します。

呼び出された関数が try/catch ブロックで「囲まれている」ことをどのように知るのでしょうか? この情報はスタック フレームにバインドされていますか? 同様に、エラー処理ブロック (一致するcatchブロックを選択するいくつかのスイッチ) へのポインターと、finallyブロックへのポインター? 上記の例で破壊的なのはなぜですかe.getMessage()(コメントを参照)。

注、私は try/catch と例外の使用方法を知っています。内部でどのように機能するか知りたいです。

4

4 に答える 4

10

「呼び出された関数が try/catch ブロックで「囲まれている」ことをどのように知るのでしょうか?」

各メソッドのコードには、そのメソッドのすべての try-catch ブロックを記述する例外テーブルが含まれています。

プロシージャ (関数、メソッド) が呼び出されると、現在のスタック フレームに呼び出し命令のアドレスが追加され、正しい命令 (呼び出し命令の次) でそのフレームの実行が復元されます。

throw ステートメントが実行されると、JVMは各スタック フレーム を調べて、そのフレームが例外を処理できるかどうかを調べます。そのメソッドに、呼び出し命令を含む try-catch ブロックが含まれていて、ブロックの例外の型がスローされた例外のスーパータイプ (または同じ) である場合に可能です。そのようなフレームが見つかった場合、そのフレームは、try-catch ブロックからポイントされた命令からその実行を復元します。

于 2013-11-04T11:19:07.097 に答える