Java中的静态内存是怎么回事?

2022-09-02 11:43:43

这个问题特别适用于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();
    }
}

答案 1

导入与编译代码中的任何指令都不相关。它们建立仅在编译时使用的别名。

有一些反射方法允许加载类但尚未初始化,但在大多数情况下,您可以假设每当引用类时,它已被初始化。

静态成员初始值设定项和静态块的执行方式就好像它们都是源代码顺序中的一个静态初始值设定项块一样。

通过静态成员变量引用的对象将被强烈引用,直到卸载该类。normal 永远不会卸载类,但应用程序服务器使用的类会在适当的条件下卸载。然而,这是一个棘手的领域,并且一直是许多难以诊断的内存泄漏的根源 - 这是不使用全局变量的另一个原因。ClassLoader


作为(切线)奖金,这里有一个需要考虑的棘手问题:

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);
  }
}

此代码将打印什么?试试看,你会看到它打印了“6”。这里有一些事情在起作用,一个是静态初始化的顺序。代码的执行方式就像是这样写的:

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. */
  }
}

答案 2

通常没有“静态”内存这样的东西。大多数 vm 都有永久生成的堆(加载类的位置),这通常不会被垃圾回收。

静态对象的分配方式与任何其他对象相同。但是,如果它们长寿,它们将在垃圾收集器的不同代际之间移动。但它们不会最终进入permgenspace。

如果您的类永久保留此对象,则只有在 vm 退出时才会释放它。


推荐