The Java Memory Architecture (1. Act)

One of the biggest strength of the Java Platform is the implementation of an automatic memory management in the Java Virtual Maschine. Everybody who has programmed with languages like C/C++ knows about the problems of managing memory allocation and deallocation in the code. With Java problems like deallocating memory too early (corrupted pointer) or too late (memory leak) cannot occur by specification. The question is: Why am I writing these blog entries?

The problem is that even with an implicit memory management integrated, Java cannot prevent application of being corrupt in sense of memory management, even it is not allowed to explicitly allocate memory in Java. The result of such wrongly programmed code normally is an exception of type: java.lang.OutOfMemoryError.

This part of the blog series about Java OutOfMemoryError, will introduce the Java Memory Architecture in detail and shows in which memory areas an java.lang.OutOfMemoryError can occur. Details about the cause of these errors and the tools and methods for analysis will be covered in later entries.

Lets start by looking at the Javadoc of java.lang.OutOfMemoryError:

Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector.

This description copied from the actual Java API Documentation (Version 6) is not only very short, but in my point of view incomplete and therefore wrong. This description does only cover the heap of the JVM – as we will learn later, OutOfMemoryError can also occur in different areas of the JVMs memory. These errors are not mentioned in the Javadoc, but you can see them every day in real world applications.

The architecture of Java’s memory management is defined for all JVM implementations in the Java Virtual Machine Specification. Chapters 3.5 Runtime Data Areas and 3.6 Frames are the most relevant for memory architecture. For a better understanding, I’ve drawn the following picture as a summary of the chapters on memory areas in a JVM.

Java Memory Architecture

We can basically distinguish memory areas that are available for all threads in a JVM and those memory areas that are exclusively accessible from only one thread. The two areas that are available from all threads are the Method Area and the Heap.

The method area is responsible for storing class information. The Class-Loader will load the bytecode of a class and will pass it to the JVM. The JVM will generate an internal class representation of the bytecode and store it in the method area. The internal representation of a class will have the following data areas:

  • Runtime Constant Pool Numeric constants of the class of types int, long, float or double, String-constants and symbolic references to all methods, attributes and types of this class.
  • Method CodeThe implementation (code) of all methods of this class including constructors etc.
  • Attributes A list of all named attributes of this class.
  • FieldsValues of all fields of this class as references to the Runtime Constant Pool.

The method area can be part of the heap and will be created at runtime. The size of the method area can be static or dynamic and it does not have to provide a Garbage Collector.

The second memory area that is available for all threads inside the JVM is the Heap. The Java heap manages instances of classes (objects) and arrays at runtime. The heap will be created at JVM startup and the size can be static or dynamic. The JVM specification mandates a Garbage Collection mechanism for reclaiming the memory of an object on the Java heap. The implementation of the Garbage Collector is not specified, but it is not allowed to provide the programmer with an explicit mechanism for deallocating the memory of an object.

Lets have a look at the Sun HotSpot implementation as an example:

sun-hotspot-memory-1

The heap is devided into two generations: The Young Generation and the Tenured Generation. The details of this “generational heap” are not relevant in the context of Java OutOfMemoryError as the design is driven by optimizations of the Garbage Collection algorithm. The method area is implemented as a separated part: The Permanent Generation. All details about configuration and monitoring of these generations will be covered in the third part of this series: “JVM Monitoring and Configuration”.

This example of the Sun HotSpot JVM memory architecure shows that the JVM specification defines how the memory inside a JVM is organized in general, but leaves enough room for implementation specific optimizations.

In addition to the heap and method area, that are available for all threads of a JVM, every thread also has exclusive access to memory that is created for each thread:

  • PC Register The Program Counter register. The register points to the current JVM instruction of the method the thread is executing, if the method is not a native method. If it is a native method the content of the PC register is not defined.
  • Java Virtual Machine Stack Each thread gets its own stack on which so called Frames are pushed for each method the thread currently executed. This means that there can be many frames on the stack for nested method calls – but there is only one frame active at the same time for one thread. The frame contains the local variables of the method, a reference to the Runtime Constant Pool of the method’s class and an operand stack for the execution of JVM operations. (The JVM is a stack machine!)
  • Native Methode Stack Native methods get its own stack, the so called „C-Stack“.

Until now you should have get an overview of the Java Memory Model including its different memory areas – this is essential, because now we will take a closer look at our java.lang.OutOfMemoryError. As mentioned before the Javadoc of this exception is not very meaningful, but the Java Virtual Machine specification defines exactly when and where Java OutOfMemoryError can occur. The difficulty is that theses errors can occur in every memory area I’ve described before. Let’s have a look at the Sun HotSpot JVM and its concrete implementation of OutOfMemoryError errors.

In the heap we get an OutOfMemoryError, if the garbage collector cannot reclaim enough memory for a new object. In such situation the Sun HotSpot JVM shows this error message:

Exception in thread "main": java.lang.OutOfMemoryError: Java heap space

A alternative for this is

Exception in thread "main": java.lang.OutOfMemoryError: Requested array size exceeds VM limit

if the application tries to create an array on the heap that is bigger than the total heap size.

If there is not enough memory in the method area for creating a new class, the Sun HotSpot implementation gets an error in the permanent generation:

Exception in thread "main": java.lang.OutOfMemoryError: PermGen space

Both kinds of OutOfMemoryError occur very often in real life and the reasons for them are very different and will be covered in later blog entries.

OutOfMemory errors in thread exclusive memory areas occur less frequently and are identified by the following error messages in the Sun HotSpot JVM:

Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread

Exception in thread "main": java.lang.OutOfMemoryError: <reason> <stacktrace> (Native method)

The first error is thrown if there are too many threads in the JVM and there is not enough memory left to create a new thread. I’ve seen this because the memory limits of a process have been reached (especially in 32bit operating systems, e.g. on Windows 32bit it is 2GB) or the maximum number of file handles for the user that executes the java process has been reached. The second error message indicates that a memory allocation error on a native stack (JNI method call) has occured.

It is also interesting that a memory allocation error on the JVM stack (too many frames on the stack) does not throw an Java OutOfMemory error but as the JVM specification mandates: java.lang.StackOverflowError.

The last variant of the OutOfMemoryError that I know of is

Exception in thread "main": java.lang.OutOfMemoryError: request <size> bytes for <reason>. Out of swap space?

This error is thrown if there is not enough memory left on the operating system level – which is normally true if other processes are using all of the available memory or the swap space is configured too small.

This first blog entry of the Java OutOfMemoryError series covered the basics of the Java Memory Architecture. In my point of view it is essential to know the different memory areas of the JVM and its functions if you want to understand why a java.lang.OutOfMemoryError occured in your application. I hope that I have made clear that there can be many variations of this error with totally different possible causes. There are a lot of open questions about when and why theses errors occur and how we can monitor and analyze memory problems in our applications. This is exactly what the next episodes ot this Java OutOfMemoryError series will cover.

  • Facebook
  • Delicious
  • Digg
  • StumbleUpon
  • Reddit
  • Blogger
  • LinkedIn
Mirko Novakovic

33 Responses to The Java Memory Architecture (1. Act)

  1. Siva says:

    Keep up the good work. I appreciate the blog. I have been looking all over the place for a clear description of the Java Memory Model without breaking my head over the Java Spec. I have not been successful in locating even a single book which talks about all aspects of the memory management in full detail. Take a look at some of these questions in my mind:
    1. Where do static values live? (In Perm Gen as per the blog)
    2. Is the Perm Gen space ever GCed? (Not mandatory according to blog)
    3. If Perm Gen is not GCed, what happens to Weak References and Soft References to static values? Do they have any effect? Is it valid to have Weak and Soft References to Static values? (Mirko, can you please help? Not sure of the answer)

  2. Mirko says:

    Hi Siva,

    thank you for your feedback. I am happy you ask these questions, as I think that some of the statements in the blog entry may be confusing…

    Static values live in the Heap and not in the Permanent Generation – except numeric constants and String-constants. As the static objects live in the Heap they are treated like “normal” objects and all rules for Weak and Soft references do apply. In most cases I see these kind of references in combination with collections and than the reference to the static collection class (e.g. a cache) is a normal reference, but the entries are references with a weak or soft reference, e.g. by using a WeakHashMap.

    The JVM specification does not mandate a garbage collection mechanism for the method area. The permanent generation of the Sun HotSpot JVM does have a Garbage Collector. If you turn on -XX:+PrintGCDetails you can see the details of the permanent generation before and after a Full GC. Only classes that are unloaded can be collected by the GC – you can see loading and unloading of classes by turning on these parameters: -XX:+TraceClassloading and -XX:+TraceClassUnloading.

    I hope this helps. more details will follow and the second part of this series will be published this week.

  3. Sebastian says:

    Hi Mirko,

    danke für diesen coolen Artikel.
    Er hat mir geholfen das Memory Modell besser verstehen zu können. Ich freu mich schon auf die nächsten Teile :)

    Viele Grüße,
    Sebastian

  4. stephan steiner says:

    Hallo Mirko

    ich bin am Zusammenstellen einer Präsentation.
    Dürfte ich Deine tollen Grafiken verwenden?

    Besten Dank
    Gruss Stephan

  5. Hallo Stephan,

    bitte einfach eine kleine “Quelle” Information drunter packen und dann kannst Du die Bilder gerne in Deiner Präsentation verwenden. Die Bilder hat übrigens Torsten aus unserem Marketing Team auf Basis meiner “Skizzen” gemacht.

    Grüße
    Mirko

  6. Pingback: Kari’s World » Blog Archive » Thanks for the memory

  7. Hi Mirko,

    nice post.

    PS: The Java Memory Model has nothing to do with garbage collections but deals with how memory behaves when multi-threading is used; so under which guarantees writes made by one thread are going to be visible in another.

    http://www.cs.umd.edu/~pugh/java/memoryModel/

  8. Hi Peter,

    I know that The Java Memory Model is more frequently used in context of the language specification http://java.sun.com/docs/books/jls/third_edition/html/memory.html#17.4 and is more relevant for concurrency issues.

    I wanted to focus on the JVM Specification part to get the java.lang.OutOfMemoryError part a bit clearer.

    Maybe I should change the name of the Blog entry, what do you think would be the best name for the JVM Specification part of the memory model?

    Maybe “Java Memory Architecture”?

    Mirko

  9. Hi Mirko,

    perhaps something with “gc configuration” could be something usable.

  10. Salih says:

    Is it possible to know in which space an instance in located? In other words lets say we have an instance of String Object “name”. Which jvm space “name” is located during execution? Is it possible to monitor its movement from surivivor space to eden space?

    Thanks.

  11. Mirko Novakovic says:

    Hi Salih,

    there is no way to get the information in which memory are an object is located during runtime from your application.

    There are some JMX information about the areas, e.g. MemoryPoolMXBean, but they do not provide object specific information.

    Maybe you could get more information via a native JVMTI agent (http://download.oracle.com/javase/6/docs/platform/jvmti/jvmti.html).

    • Andy Song says:

      Hi Mirko,

      Actually if we use sun jdk, we have the ability to get object address via “sun.misc.Unsafe”

      static long toAddress(Object obj) {
      Object[] array = new Object[] {obj};
      long baseOffset = getUnsafe().arrayBaseOffset(Object[].class);
      return normalize(getUnsafe().getInt(array, baseOffset));
      }

      static Object fromAddress(long address) {
      Object[] array = new Object[] {null};
      long baseOffset = getUnsafe().arrayBaseOffset(Object[].class);
      getUnsafe().putLong(array, baseOffset, address);
      return array[0];
      }

      Please enjoy that.

  12. Macluq says:

    Hi, just pointing out a typo: Maschine in German. Machine in English. 😉

    Thanks for the stuff, it’s pretty cool.

  13. Vamshi says:

    Very informative…thanks

  14. Srinivasan says:

    Excellent diagram which shows the Java Memory architecture. This kind of article i have been searching for a long time. I shall have to go through it line by line.

  15. Congratulations for the excellent article!!! It really clarifies the main aspects of the Java memory architecture and management.

    I guess the link “optimizations of the Garbage Collection algorithm” should be poiting to http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html instead.

  16. Günther says:

    Hallo Mirko,

    verstehe ich es in deiner Grafik richtig, dass jeder Java Thread außerhalb des Heaps/Perm Heaps einen Teil vom RAM belegt? z.B. hatten wir in einer 32bit JVM (auf 64 bit SPARC) die PermSize auf 512 MB, MaxHeap auf 3,2 GB und ziemlich viele Threads offen. Die JVM wurde innerhalb von Minuten instabil und die HeapUsage lag bei 100 %.
    Wenn jeder Thread einen Stack außerhalb des Heaps bekommt, wieviel RAM wird diesem Thread zugewiesen?

    Beste Grüße
    Günther

    • Mirko Novakovic says:

      Hallo Günther,

      das siehst Du richtig – jederr Stack belegt einen Anteil im Memory ausserhalb des Heaps. Den Wert kannst Du über -Xss konfigurieren bzw. über eine Limitierung der Thread Stack Size auf OS Ebene. Die Größe des belegten Speichers je Thread hängt vom OS ab.

      Dein beschriebenes Problem muss aber nicht unbedingt mit den Threads zusammen hängen, da ja der Heap voll gelaufen ist. Am Besten Dump ziehen und reinschauen. Fabian hat ja in Teil 4 beschrieben, wie man das am Besten macht und zeigt in Teil 5 bald noch elegantere Wege mit entsprechenden Tools.

      Grüße
      Mirko

      • Günther says:

        Hallo nochmal,

        danke für deine ausführliche Antwort. Da wir aber auch “java.lang.OutOfMemoryError: unable to create new native thread” Errors hatten, besteht trotzdem die Vermutung, dass insgesamt nicht genug RAM zur Verfügung stand. Habe aber bereits einen Dump gezogen und werde ihn analysieren.

        Beste Grüße
        Günther

        • Fabian Lange says:

          Hallo Günther,
          klingt interessant! Mich interessiert auf jeden Fall die Ursache. Bisher ist mir sowas nur bei fehlerhafter Threadbenutzung begegnet. Hat sich immer mit einer ExecuterService/ThreadPool Lösung lösen lassen. Der Code wurde meist sauberer und zur Verwunderung der Entickler trotz Threadbegrenzung nichtmal langsamer. Tja eine JVM kann nun auch keine Prozessorkerne durch new Thread() herzaubern. Stichwort Starvation.

          Viele Grüße
          Fabian

          • Günther says:

            Hallo Fabian,
            fehlerhafte Threadbenutzung ist ein sehr guter Ansatz.
            Der Code wurde seit 2004 weiterentwickelt, unzählige
            Programmierer waren beteiligt und jeder hat seine Ansichten dazu beigetragen. Wir sind schon dabei, den Code
            zu analysieren. Dieser ExecuterService-Ansatz klingt
            interessant, dazu muss mal gegoogled werden 😉

            Ein weiterer Ansatzpunkt ist insbesondere unter Solaris auch die ThreadStackSize – wenn unter einer 32bit-JVM zuviel Heap gegeben wird, bleibt für die Stacks der Threads anscheinend zu wenig RAM übrig. Solaris hat dazu angeblich eine Standardgröße von 1 oder 2 MByte / Stack (je nachdem, ob 32 oder 64bit Solaris). Dh. da könnte uns einiges an Speicher abhanden kommen und wir experimentieren schon mit -Xss, um die ThreadStackSize auf 128k zu begrenzen.

            VG
            Günther

  17. Mirko,

    thank you very much for this interesting post. It filled the gap between theory (heap, stack, etc) and practice (PermGen space error).

    I did not understand one paragraph:
    “The method area can be part of the heap and will be created at runtime. The size of the method area can be static or dynamic and it does not have to provide a Garbage Collector.”
    What do you mean by “provide a Garbage Collector” ?


    Cheers,
    TomekThe method area can be part of the heap and will be created at runtime. The size of the method area can be static or dynamic and it does not have to provide a Garbage Collector.

    • Mirko Novakovic says:

      Hi Tomek,

      this means that the specification does not require the method area to have a garbage collector.

      Mirko

  18. Prakash Raju says:

    Thank you so much Mirko.

    It’s very help full to people like us.

  19. Prakash says:

    really good one.Its helpful.

  20. dori says:

    Hi!
    How can help me with some exmaple in JMM.

  21. Binh Thanh Nguyen says:

    Thanks. Nice post

  22. Nilesh says:

    1- how the perm area memory is freed? Is it always grows?
    2- All the consts goes to perm area. So which one is fatser perm or heap ?

  23. Sushma says:

    Very Nice article on JVMMemory model…
    Thank u so much for this post :)

  24. Tapan says:

    Good Explanation Mirko.

  25. Parixit Singh says:

    Thank You very much for the blog.
    It cleared my concept on the various areas of the java program. I was very confused earlier now i am clear with the topic Thank you once again

    Good Work..

  26. Guido Stoff says:

    Hallo,

    ich habe immer wieder folgenden Fehler. Ich arbeitete mit recht großen Grafiken 9000×6000 Pixel und drawe sie mit dem Befehl g2d.drawImage(img, affineTransform, this); auf eine Graphics. Wenn die Grafiken kleiner sind läuft das Programm.
    Hat jemand eine Ahnung welcher Speicherbereich hier betroffen ist und wie man Abhilfe schaffen könnte?

    1 W:\akg\Druck_OK\42882.jpg– nach Spiegelung — Free Memory: 1024315352 bytes
    1 W:\akg\Druck_OK\42882.jpg– vor Draw Image — Free Memory: 1024315352 bytes
    java.lang.OutOfMemoryError
    Exception in thread “AWT-EventQueue-0″ java.lang.InternalError: Problem in WPrin
    terJob_drawDIBImage
    at sun.awt.windows.WPrinterJob.drawDIBImage(Native Method)
    at sun.awt.windows.WPrinterJob.drawDIBImage(Unknown Source)
    at sun.awt.windows.WPathGraphics.drawImageToPlatform(Unknown Source)
    at sun.print.PathGraphics.drawImage(Unknown Source)

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>