怎么了java中的静态内存?

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

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

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

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

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

通常没有“静态”记忆这样的东西。 大多数虚拟机具有堆的永久生成(其中类被加载),这通常不是垃圾收集的。

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

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

只要在代码中引用了类,就会初始化此静态变量some0 。 在您的示例中,这将在main方法的第一行中执行。

您可以通过创建静态初始化程序块来validation这一点。 在此初始化程序块中放置一个断点,您将看到它何时被调用。 或者更简单……在SomeObject的构造函数中放置一个断点。

第2.11节太阳JVM规范的静态初始化程序中介绍了静态变量的初始化 。 规范没有定义垃圾收集的实现,但是我想静态对象的垃圾收集规则会因VM而异。

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

因此,指针引用的Object位于普通堆中,就像任何其他对象一样。

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

如果类本身被卸载并且从堆中剪切整个对象图,它也可以是自由的(即使不是空的)。 当然,当一个类可以被卸载是一个很好的主题,以解决许多其他问题…… 🙂