19

This question is for the java language in particular. I understand that there is a static protion of memory set aside for all static code.

My question is how is this static memory filled? Is a static object put into static memory at import, or at first reference? Also, do the same garbage collection rules apply to static objects as they do for all other objects?


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();
    }
}
ForYourOwnGood
  • 38,822
  • 5
  • 30
  • 27

6 Answers6

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. */
  }
}
erickson
  • 265,237
  • 58
  • 395
  • 493
  • Why do you say that the system class loader never unloads any classes? It seems that only the **bootstrap** class loader do not unload classes http://stackoverflow.com/a/453073/632951 – Pacerier Aug 23 '14 at 05:52
  • I didn't say that the system class loader never unloads any classes. I said a normal `ClassLoader` never unloads a class. The system class loader is not normal; it's a special class loader created by the runtime. I don't know whether its possible to unload it, but I know I've never seen it done. – erickson Aug 23 '14 at 06:44
  • What do you mean by a "normal" classloader? It seems that every single class (except for those loaded by the bootstrap loader) can be unloaded... – Pacerier Aug 23 '14 at 06:49
  • Yes, it is *permissible* under the JLS for a JVM to unload the system class loader. How often does it happen? Would you consider the necessary manipulation of the class loader (system or otherwise) to be atypical? The point of my answer is that unless deliberate action is taken, a class stays loaded. – erickson Aug 23 '14 at 07:29
  • Doesn't typical JVMs already unload classes whenever memory is running low? – Pacerier Aug 23 '14 at 07:48
  • My understanding is that the class loader has to be unloaded together with all its classes. I infer from this that if all the application classes are loaded from the system class loader, none will be unloaded even if `OutOfMemoryError` is the alternative. Of course, environments like an RCP or application server typically create many class loaders, and are likely to be able to discard these loaders and their classes. I'm talking more about a straightforward standalone application with a `main()` method. – erickson Aug 23 '14 at 07:55
  • Do you have a citation or source for "class loader has to be unloaded together with all its classes"? It seems to me that the system class loader can unload a class which was used but no longer has any instances/references, then reload it again if the application creates a new instance of the class again, then unload it again when those instances/references are gone, then reload it again if needed, then unload it again etc etc... It's just basic GC behavior. – Pacerier Aug 23 '14 at 08:06
  • @Pacerier You provided the reference above. JLS 12.7 explains very clearly why it is not possible to safely *reload* a class, and why classes can be unloaded *only* when their loader is unreachable. While it would be permissible strictly speaking to GC a class without GC-ing its loader, its loader must have been identified as garbage, and therefore in practice I assume it would be reclaimed with all its classes at once. – erickson Aug 23 '14 at 19:45
  • Let me be clear, there's **two kinds of unload**: The first is when we unload and reload and the application calling code may see a difference—I call this **dumb-unload**. The other kind is when we unload and reload and the application will not *see* any semantic difference (transparent)—I call this **trans-unload**. The last paragraph of JLS 12.7 made it clear that the entire section is talking about dumb-unload. This means that even when a class loader is still referenced by the application, it's allowed to trans-unload its classes that are no longer used, ......... – Pacerier Aug 24 '14 at 11:21
  • ...........It stated that trans-unload may be impossible due to **2** points. But that's a *"may"* not a *"must"*. **Point 1)** regarding "static native/non-native state" —— We can simply solve this by saving the static state while removing the class definition from memory. For example, all static variables *V1*, *V2*, *V3* of class `C1`, `C2`, `C3` etc can be attached to our classloader. Therefore if `C1` has a static instance *C1V1* of type `C2`, then *C1V1* instance is not attached to C1's class definition, but attached directly to our class loader. This way............. – Pacerier Aug 24 '14 at 11:22
  • ...........all native/non-native static states are maintained even when we *reload* `C1`. **Point 2)** regarding "hash value may change" —— We can simply solve this by treating the hash value as a static state and applying the solution above. In other words, the hash value is maintained even when the class definition is removed from memory. – Pacerier Aug 24 '14 at 11:22
  • That makes sense. Which JVMs or class loaders implement this sort of class memoization? – erickson Aug 25 '14 at 01:08
  • I don't have info on the workings of typical JVM implementations, which is why when you claim "class stays loaded in a typical JVM", I asked (above) "doesn't typical JVMs already unload classes whenever memory is running low?". Do you have a citation/source for the claim "class stays loaded in a typical JVM"? – Pacerier Aug 25 '14 at 02:32
  • @Pacerier your idea of “transparent unloading”, i.e. unloading everything that can be reconstructed, but transparently keep the initialization state and `static` fields, could be interpreted as “actually not unloading, but drop reconstructable data”. In that regard, some of these things do happen today, e.g. when a “shared class data” archive is being used, it is memory mapped into the process and hence, parts of it may get transparently removed from physical memory and reloaded by the operating system. Further, rarely used code may get deoptimized, dropping the compiled code. Close enough… – Holger Jan 23 '18 at 14:02
5

There is normally no such thing as "static" memory. Most vm's have the permanent generation of the heap (where classes get loaded), which is normally not garbage collected.

Static objects are allocated just like any other object. But, if they live for long they will be moved between the different generations in the garbage collector. But they will not end up in permgenspace.

If your class is holding onto this object permanently, it will only be released when the vm exits.

krosenvold
  • 75,535
  • 32
  • 152
  • 208
3

This static variable some0 is initialized as soon as your class is referenced in your code. In your example this will be executed in first line of your main method.

You can validate this by creating a static initializer block. Put a break point in this initializer block and you'll see, when it will be called. Or even more simplier... put a breakpoint in the constructor of SomeObject.

Yaba
  • 5,979
  • 8
  • 38
  • 44
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.

Kevin Loney
  • 7,483
  • 3
  • 28
  • 33
2

It should be noted, that only the pointer (or any other primitive type) is stored in the PermGenSpace (thats the proper name for the area where the static stuff is stored).

So the Object referenced by the pointer sits in the normal heap, like any other object.

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
0

If the static field is changed to reference a different object, the original object pointed to by the static field is eligible for GC just like any other object.

It could also be free'ed (even if not nulled) if the class itself is unloaded and the entire object graph is cut from the heap. Of course, when a class can be unloaded is a good topic for a host of other questions... :)

Alex Miller
  • 69,183
  • 25
  • 122
  • 167