Thursday, June 28, 2012

JVM Memory Structure

  • JVM has subsystems for memory areas, data types, and instructions. When a Java application starts, a runtime instance is born. When the application completes, the instance dies. 
  • A Java virtual machine instance starts running its application by invoking the main() method of some initial class. The main() method must be public, static, return void, and accept one parameter: a String array. Any class with such a main() method can be used as the starting point for a Java application. 
  • If you start three Java applications at the same time, on the same computer, using the same concrete implementation, you'll get three Java virtual machine instances. Each Java application runs inside its own Java virtual machine.

  • The block diagram of the JVM is as follows.
Each JVM has a Class Loader Subsystem and a Execution Engine.

Class Loader Subsystem:  A mechanism for loading types (classes and interfaces) given fully qualified names
Execution Engine: A mechanism responsible for executing the instructions contained in the methods of loaded classes.

When a Java program started Java Virtual Machine needs memory to store many thing about the program, for example, JVM needs memory for below data,

Bytecodes 
Objects the program instantiates
Parameters to methods
Return values
Local variables
Intermediate results of computations

So JVM organizes these information into several different runtime data areas in the JVM. Some runtime data areas are shared among all of an application's threads and others are unique to individual threads.
Each instance of the Java virtual machine has one method area and one heap. These areas are shared by all threads running inside the virtual machine. 
When the virtual machine loads a class file, it parses information about a type from the binary data contained in the class file. It places this type information into the method area. As the program runs, the virtual machine places all objects the program instantiates onto the heap.
As each new thread comes into action, it gets its own pc register (program counter) and Java stack. If the thread is executing a Java method (not a native method), the value of the pc register indicates the next instruction to execute. 

A thread's Java stack stores the state of Java (not native) method invocations for the thread. The state of a Java method invocation includes its local variables, the parameters with which it was invoked, its return value (if any), and intermediate calculations. The state of native method invocations is stored in an implementation-dependent way in native method stacks, as well as possibly in registers or other implementation-dependent memory areas. 


Heap Generations 

Java objects are created in Heap and Heap is divided into three parts or generations for sake of garbage collection, namely Young generation, Tenured or Old Generation and Perm Area of heap.

Heap
|---- Young generation
| ---- Tenured
| ---- Perm Area
Young Generation area on the heap can be further divided as Eden space, Survivor 1 and Survivor 2 space
Young Generation
| ---- Eden space
| ---- Survivor 1
| ---- Survivor 2
New objects are created in the Eden space, if the object survives after minor garbage collection it moves to Survivor 1 and then Survivor 2. 
After objects "survive" repeated garbage collections in the Young Generation they are migrated to the Tenured Generation.

The Permanent Generation is a special case, it contains objects that are needed by the JVM, basically it used to store Meta data related to classes and methods in JVM it also hosts String pool provided by JVM. There are many opinions around whether garbage collection in Java happens in perm area of java heap or not, as per my knowledge this is something which is JVM dependent and happens at least in Sun's implementation of JVM. 

Increasing Java Heap Size

When the application is larger and lots of object created you might need to increase the heap size. Default heap size is sufficient for a small or medium scale application. 
Default heap size is 128MB in a typical 32-bit in a Sun's JVM. You can use command line parameters to increase heap size according to your application's need. But you can not change the heap size dynamically, these parameters are read at the time of JVM starts up.

-Xms - starting size of the heap
-Xmx - maximum size of the heap
-Xmn - size of the new generation of the heap

When JVM starts JVM heap space is the initial size of Heap specified by -Xms parameter.
As the application is running objects are created and JVM heap size is expanded to accommodate for new objects. 
JVM invokes the GC to reclaim memory from unused objects and JVM expands the Heap size in JVM upto some where near to Maximum Heap Size specified by -Xmx.
If there is no more memory left for creating new object in the heap, JVM throws  java.lang.outofmemoryerror and  your application crashes. Just before throwing OutOfMemoryError No Space in Java Heap, JVM tries to run garbage collector to free any available space but even after that there is no much space is available on the Heap it results into OutOfMemoryError. 
To resolve this error you need to understand your application object profile i.e. what kind of object you are creating, which objects are taking how much memory etc. 
For analyzing the heap you can use a profiler or heap analyzer to troubleshoot OutOfMemoryError in Java.  
"java.lang.OutOfMemoryError: Java heap space" error messages denotes that Java heap does not have sufficient space and cannot be expanded further.
"java.lang.OutOfMemoryError: PermGen space" error message comes when the permanent generation of Java Heap is full, the application will fail to load a class or to allocate an interned string.
Java Heap dump is a snapshot of Java Heap Memory at a particular time. This is very useful to analyze or troubleshoot any memory leak in Java or any Java.lang.outofmemoryerror. 
There is tools available inside JDK which helps you to take heap dump and there are heap analyzer available tool which helps you to analyze java heap dump. You can use "jmap" command to get java heap dump, this will create heap dump file and then you can use "jhat - Java Heap Analysis Tool" to analyze those heap dumps. 
More Information to Java Garbage Collector.
  
To solve "java.lang.OutOfMemoryError: PermGen space" you need to increase the perm gen memory. Increase size of PermGen Space by using JVM param -XX:MaxPermSize and -XX:PermSize.
set JAVA_OPTS="-Xms1024m -Xmx10246m -XX:NewSize=256m -XX:MaxNewSize=356m -XX:PermSize=256m -XX:MaxPermSize=356m"