java中的静态内存怎么了?

java中的静态内存怎么了?,java,memory-management,static,Java,Memory Management,Static,这个问题特别针对java语言。我知道所有静态代码都有一个静态内存保护 我的问题是这个静态内存是如何填充的?静态对象是在导入时还是在第一次引用时放入静态内存?同样,垃圾收集规则是否适用于静态对象,就像它们适用于所有其他对象一样 public class Example{ public static SomeObject someO = new SomeObject(); } /********************************/ // Is the static objec

这个问题特别针对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();
    }
}

通常没有“静态”内存。大多数虚拟机都有永久性的堆生成(类在其中加载),通常不会进行垃圾收集

静态对象的分配与任何其他对象一样。但是,如果它们活得长,它们将在垃圾收集器中的不同世代之间移动。但它们最终不会进入永久空间


如果您的类永久保留此对象,则仅当vm退出时才会释放此对象。

此静态变量some0在代码中引用您的类后立即初始化。在您的示例中,这将在主方法的第一行执行


您可以通过创建静态初始值设定项块来验证这一点。在这个初始值设定项块中放置一个断点,您将看到何时调用它。或者更简单一些。。。在SomeObject的构造函数中放置一个断点。

静态变量的初始化在suns JVM规范的一节中介绍。该规范没有定义垃圾收集的实现,但是,我认为静态对象的垃圾收集规则会因您的VM而异。

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

有些反射方法允许加载类但尚未初始化,但在大多数情况下,您可以假设只要引用了类,它就已经初始化

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

通过静态成员变量引用的对象将被强引用,直到类被卸载。普通的
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. */
  }
}

应该注意的是,只有指针(或任何其他原语类型)存储在中(这是存储静态内容的区域的正确名称)


因此,指针引用的对象与任何其他对象一样位于正常堆中。

如果静态字段更改为引用不同的对象,则静态字段指向的原始对象与任何其他对象一样符合GC的条件


如果类本身被卸载并且整个对象图从堆中剪切,那么它也可以被释放(即使没有为null)。当然,当一个类可以卸载时,对于许多其他问题来说是一个很好的话题…:)

为什么说系统类加载器从不卸载任何类?似乎只有引导类加载器不卸载类,我没有说系统类加载器从不卸载任何类。我说过普通的
类加载器从来不会卸载类。系统类装入器不正常;它是由运行时创建的特殊类装入器。我不知道是否可以卸载它,但我知道我从未见过它被卸载。你说的“普通”类加载器是什么意思?似乎每个类(除了引导加载程序加载的类)都可以卸载……是的,JLS允许JVM卸载系统类加载程序。多久发生一次?您是否认为必要的操纵类加载器(系统或其他)是非典型的?我的答案是,除非采取有意的行动,否则类将保持加载状态。当内存不足时,典型的JVM不是已经卸载了类吗?