代码之家  ›  专栏  ›  技术社区  ›  ForYourOwnGood

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

  •  19
  • ForYourOwnGood  · 技术社区  · 16 年前

    这个问题特别针对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();
        }
    }
    
    6 回复  |  直到 16 年前
        1
  •  34
  •   erickson    16 年前

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

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

    静态成员初始化器和静态块被执行,就像它们在源代码顺序中都是一个静态初始化器块一样。

    通过静态成员变量引用的对象将被强引用,直到类被卸载。一个正常的 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
  •  5
  •   krosenvold    16 年前

    通常不存在所谓的“静态”记忆。大多数虚拟机都有永久生成的堆(类加载的地方),通常不会进行垃圾回收。

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

    如果你的类永久地持有这个对象,那么只有当vm退出时,它才会被释放。

        3
  •  3
  •   Yaba    16 年前

    此静态变量 某人0 一旦你的类在代码中被引用,它就会被初始化。在您的示例中,这将在main方法的第一行执行。

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

        4
  •  3
  •   Kevin Loney    16 年前

    静态变量的初始化在第节中介绍 2.11 Static Initializers 然而,该规范没有定义垃圾收集的实现,因此我认为静态对象的垃圾收集规则会因VM而异。

        5
  •  2
  •   Bill the Lizard    13 年前

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

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

        6
  •  0
  •   Alex Miller    16 年前

    如果静态字段被更改为引用不同的对象,则静态字段指向的原始对象与任何其他对象一样有资格进行GC。

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