5

これについて多くのトピックやリソースがあることは知っていますが、非常に具体的な質問について疑問に思っています (すべてのソースをチェックして明確な答えを得るには非常に長い時間がかかる場合があります)。

final staticJVM/Dalvik は、クラスの静的フィールド (プリミティブ値を除く) にアクセスするまでに、クラスの静的フィールドが既に初期化されていることを保証していることを知っています。逆もまた然り?クラスにまったくアクセスしない場合(たとえば、別の静的メソッドのコードが特定のブランチに到達しないため)、VM がこのクラスの静的を初期化しないswitch-caseことが保証されますか?

次のようなクラスがあるとします。

public class Boo {
      public static int[] anything = new int[] { 2,3,4 };
      private static int[] something = new int[] { 5,6,7 }; // this may be much bigger as well

      public static final int[] getAndClear() {
           int[] st = something;
           something = null;
           return st;
      }
}

Boo私のアプリケーションは非常に特別なもので (一部の点では典型的ではありません)、 (コード ジェネレーターによって生成された)などの数百のクラスを保持するsomething場合があります。まあ時々)。

アプリケーションの入力によっては、これらの事前生成されたクラスの多くがアクセスされない場合があります。多くのオブジェクトが不必要に初期化されて、多くのメモリが消費されることは望ましくありません。int[]

4

1 に答える 1

9

JVM/Dalvik は、クラスの静的フィールド (最終的な静的プリミティブ値を除く) にアクセスするまでに、クラスの静的フィールドが既に初期化されていることを保証していることを知っています。

これはほとんどの場合当てはまりますが、一定のインライン展開があるため、特定の静的フィールドには当てはまりません。の

class A {
  public static final String FOO = "foo";

  static { System.out.println("loaded A"); }
}

public class B {
  public static void main(String... argv) {
    System.out.println("Got " + A.FOO);
  }
}

JVM は「Got foo」を出力しますが、「loaded A」を出力しません。実際、 がクラスパス上にない場合でも B は実行されますが、コンパイル時にまたはA.classの少なくとも 1 つが利用可能でなければなりません。A.javaA.classB.java


逆もまた然り?クラスにまったくアクセスしない場合 (たとえば、別の静的メソッドの switch-case コードが特定のブランチに到達しないため)、VM がこのクラスの静的を初期化しないことが保証されますか?

はい。JLS は、クラスのロードと初期化が発生する正確な条件を提示するため、JVM 実装にはクラスを積極的にロードまたは初期化する自由がありません。

12.4.1は興味深い章です。

12.4.1. 初期化が発生する場合

クラスまたはインターフェイスの型 T は、次のいずれかが最初に発生する直前に初期化されます。

  1. T はクラスであり、T のインスタンスが作成されます。
  2. T はクラスであり、T によって宣言された静的メソッドが呼び出されます。
  3. T によって宣言された static フィールドが割り当てられます。
  4. T によって宣言された静的フィールドが使用され、そのフィールドは定数変数ではありません (§4.12.4)。
  5. T は最上位クラス (§7.6) であり、T (§8.1.3) 内で語彙的にネストされた assert ステートメント (§14.10) が実行されます。

「直前」という言い回しは熱心さを禁じており、2 つのクラスが両方とも上記のアクションのいずれかを実行しようとしたときに何が起こるかを義務付けています。ロードされているが初期化されていないクラスに関連付けられたロックがあり、両方とも最初にそれを取得するスレッドまで待機します。 lock は初期化を実行します。

「フィールドは定数変数ではありません (§4.12.4)」という言い回しは、上で説明したルールの例外class BですA.FOO


public static final int[] getAndClear() { ... }

synchronizedそうしないと、2 つのスレッドが両方とも同じ配列を受け取る代わりに同じ配列を取得する可能性があるためですnull。上で述べたクラス・ローダー・ロックは を保護しませんgetAndClear

于 2012-10-26T18:13:03.157 に答える