The Java Memory Architecture (1. Act)

33 Comments

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.

Author

Mirko Novakovic

Share on FacebookGoogle+Share on LinkedInTweet about this on TwitterShare on RedditDigg thisShare on StumbleUpon

Kommentare

  • March 8, 2011 von Salih

    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.

  • March 22, 2011 von Macluq

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

    Thanks for the stuff, it’s pretty cool.

  • June 20, 2011 von Vamshi

    Very informative…thanks

  • July 22, 2011 von Srinivasan

    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.

  • 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.

  • 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.

    • January 18, 2012 von Mirko Novakovic

      Hi Tomek,

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

      Mirko

  • January 20, 2012 von Prakash Raju

    Thank you so much Mirko.

    It’s very help full to people like us.

  • March 21, 2012 von Prakash

    really good one.Its helpful.

  • April 27, 2012 von dori

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

  • August 20, 2013 von Binh Thanh Nguyen

    Thanks. Nice post

  • August 26, 2013 von Nilesh

    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 ?

  • March 12, 2014 von Sushma

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

  • April 12, 2014 von Tapan

    Good Explanation Mirko.

  • September 2, 2014 von Parixit Singh

    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..

Comment

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