7

ガベージコレクターからこの奇妙な動作を見ることができます

public class A {
    public static void main(String[] args) {

        String foo;
        try {
            foo = "bar";

            int yoo = 5; //1
        } catch (Exception e) {
        }

        int foobar = 3;//2 
    }
}

デバッグに行き、//1 foo にブレークポイントを設定し、その値が "bar" であるが、ブレークポイント //2 foo が null である場合、デバッグ中にこれを理解するのが難しい場合があります。私の質問は、これがガベージ コレクターからの合法的な動作であると言う仕様があるかどうかです。

この小さなバリエーションでは、ガベージが収集されません。

public class A {
    public static void main(String[] args) {

        String foo;
        try {
            foo = "bar";
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        int foobar = 3;
    }
}

なんで?

4

4 に答える 4

9

この場合、設定後に foo 変数を使用しないため、JVM が変数を完全に無視することは合法です。変数は決して使用されず、プログラムの結果は変わらないからです。

ただし、デバッグ モードでは起こりそうにありません。

あなたの場合、 foo は、スコープ内にあるか、try/catch ブロックの後のセクションを含む参照を保持している限り、GC されるべきではありません。

編集

実際、Java 7.0_03を使用したNetbeans 7.1.1で説明したのと同じ動作が得られます...

問題の 1 つは、デフォルト値を に設定していないためfoo、try/catch ブロックの後で使用できないことです (コンパイルされません)。

バイトコード

  • 使用するコードで
public static void main(java.lang.String[]);
Code:
   0: ldc           #2                  // String bar
   2: astore_1      
   3: iconst_5      
   4: istore_2      
   5: goto          9
   8: astore_2      
   9: iconst_3      
  10: istore_2      
  11: return        
  • 最初のステートメントとして使用String foo = null;します。この場合、デバッガーは try/catch ブロックの後に値を確認します。
public static void main(java.lang.String[]);
Code:
   0: aconst_null   
   1: astore_1      
   2: ldc           #2                  // String bar
   4: astore_1      
   5: iconst_5      
   6: istore_2      
   7: goto          11
  10: astore_2      
  11: iconst_3      
  12: istore_2      
  13: return        

私はバイトコードの専門家ではありませんが、私と非常によく似ています...

結論

私の個人的な結論は、デバッガーが の値を表示するには、何らかの種類fooの a を実行する必要があるということです。これは、初期化されていない可能性があるため、catch ブロックの後に有効なステートメントではありません。そのセクションにa を追加することは正しくありません (コンパイルされません)。デバッガーは、値が何であり、何を示しているかについて少し迷っています。foo.toString()fooSystem.out.println(foo)null

これが GC とは何の関係もないことを納得させるために、次の例を試すことができます。

public static void main(String[] args){
    String foo;
    char[] c = null;
    try {
        foo = "bar";
        c = foo.toCharArray();

        int yoo = 5; //1
    } catch (Exception e) {
    }

    int foobar = 3;//2 
}

行では、それが成り立つのfoobarを見ることができますが、 foo は と表示されます。したがって、文字列はまだ存在しますが、デバッガーはそれを表示できません。cbarnull

さらに面白い例:

public static void main(String[] args){
    String foo;
    List<String> list = new ArrayList<String>();

    try {
        foo = "bar";
        list.add(foo);
        int yoo = 5; //1
    } catch (Exception e) {
    }

    int foobar = 3;//2 

}

foobar行では、とfoo表示されますnullが、list含まれているのは"bar"... いいね。

于 2012-07-13T16:45:47.353 に答える
2

生成されたバイトコードは次のとおりです。

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String bar
       2: astore_1
       3: iconst_5
       4: istore_2
       5: goto          9
       8: astore_2
       9: iconst_3
      10: istore_2
      11: return
    Exception table:
       from    to  target type
           0     5     8   Class java/lang/Exception

私の最初の推測では、ローカル変数の位置を foo と foobar の両方に再利用すると、デバッグ時に値を表示できなくなります。しかし、見ることができるように、 local 1 は上書きされません (ただし、yoo と foobar は同じスペースを共有しています)。

これは発生せず、JIT がここで何もしていないことは非常に確信できるため、これは非常に奇妙な動作です。

于 2012-07-13T16:56:33.057 に答える
2

fooデフォルト値はありません.2行目に行くと、それが設定されたスコープの外に出ています。

于 2012-07-13T16:48:02.513 に答える
-2

main メソッドのコンテキストがまだ有効であるため、これは正当な動作ではありません。try ブロックで文字列 foo を宣言しない限り、理想的には GC されるべきではありません (この場合、2 でアクセスできません)。

このコードを試してみましたが、うまくいきました。

于 2012-07-13T16:51:43.100 に答える