19

この質問は、特に Java 言語に関するものです。すべての静的コード用に確保されているメモリの静的部分があることを理解しています。

私の質問は、この静的メモリがどのように満たされているのですか? 静的オブジェクトは、インポート時または最初の参照時に静的メモリに配置されますか? また、他のすべてのオブジェクトと同じガベージ コレクション規則が静的オブジェクトに適用されますか?


public class Example{
    public static SomeObject someO = new SomeObject();
}
/********************************/
// Is the static object put into static memory at this point?
import somepackage.Example;

public class MainApp{
    public static void main( Sting args[] ){
// Or is the static object put into memory at first reference?
       Example.someO.someMethod();
// Do the same garbage collection rules apply to a 
//     static object as they do all others?
       Example.someO = null;
       System.gc();
    }
}
4

6 に答える 6

34

Imports don't correlate with any instructions in compiled code. They establish aliases for use at compile time only.

There are some reflective methods that allow the class to be loaded but not yet initialized, but in most cases, you can assume that whenever a class is referenced, it has been initialized.

Static member initializers and static blocks are executed as if they were all one static initializer block in source code order.

An object referenced through a static member variable is strongly referenced until the class is unloaded. A normal ClassLoader never unloads a class, but those used by application servers do under the right conditions. However, it's a tricky area and has been the source of many hard-to-diagnose memory leaks—yet another reason not to use global variables.


As a (tangential) bonus, here's a tricky question to consider:

public class Foo {
  private static Foo instance = new Foo();
  private static final int DELTA = 6;
  private static int BASE = 7;
  private int x;
  private Foo() {
    x = BASE + DELTA;
  }
  public static void main(String... argv) {
    System.out.println(Foo.instance.x);
  }
}

What will this code print? Try it, and you'll see that it prints "6". There are a few things at work here, and one is the order of static initialization. The code is executed as if it were written like this:

public class Foo {
  private static Foo instance;
  private static final int DELTA = 6;
  private static int BASE;
  static {
    instance = null;
    BASE = 0;
    instance = new Foo(); /* BASE is 0 when instance.x is computed. */
    BASE = 7;
  }
  private int x;
  private Foo() {
    x = BASE + 6; /* "6" is inlined, because it's a constant. */
  }
}
于 2009-01-01T20:04:24.657 に答える
5

通常、「静的」メモリなどはありません。ほとんどの vm には、ヒープ (クラスがロードされる場所) の永続的な生成があり、通常、ガベージ コレクションは行われません。

静的オブジェクトは、他のオブジェクトと同様に割り当てられます。しかし、彼らが長く生きていると、ガベージ コレクター内の異なる世代間で移動されます。しかし、それらは permgenspace にはなりません。

クラスがこのオブジェクトを永続的に保持している場合、vm が終了したときにのみ解放されます。

于 2009-01-01T19:50:46.027 に答える
3

The initialization of static variables is covered in Section 2.11 Static Initializers of suns JVM spec. The specification does not define the implementation of Garbage collection however so I imagine that garbage collection rules for static objects will vary depending on your VM.

于 2009-01-01T20:01:37.423 に答える
3

この静的変数some0は、クラスがコードで参照されるとすぐに初期化されます。あなたの例では、これはメインメソッドの最初の行で実行されます。

これは、静的初期化ブロックを作成することで検証できます。このイニシャライザ ブロックにブレーク ポイントを配置すると、いつ呼び出されるかがわかります。または、さらに単純に... SomeObject のコンストラクターにブレークポイントを配置します。

于 2009-01-01T19:50:53.530 に答える
2

PermGenSpace(静的なものが格納される領域の適切な名前)には、ポインター(またはその他のプリミティブ型)のみが格納されることに注意してください 。

したがって、ポインタによって参照されるオブジェクトは、他のオブジェクトと同様に、通常のヒープ内にあります。

于 2009-01-02T00:16:59.810 に答える
0

静的フィールドが別のオブジェクトを参照するように変更された場合、静的フィールドが指す元のオブジェクトは、他のオブジェクトと同様に GC の対象となります。

クラス自体がアンロードされ、オブジェクト グラフ全体がヒープから切り取られた場合は、(null ではない場合でも) 解放される可能性があります。もちろん、クラスをいつアンロードできるかは、他の多くの質問にとって良いトピックです... :)

于 2009-01-02T04:13:26.917 に答える