What is Java Memory Model and Why it is Important?
The Java memory model specifies how the Java virtual machine works with the computer’s memory (RAM).
It is very important to understand the Java memory model if you want to design correctly behaving concurrent programs. The Java memory model specifies how and when different threads can see values written to shared variables by other threads, and how to synchronize access to shared variables when necessary.
Java Memory Model : Heap and Stack
Internal memory model in java, divides the JVM memory into two areas.
- Stack (known as Thread Stack)
The heap is where all the objects live and the stacks are where the threads do their work. Please refer the below diagram.
There is a single heap per JVM and conceptually, there can be multiple thread stacks depending on the number of threads, but it can be limited by the OS based on the available resources (such as memory). Thread stack is local for each thread and heap is shared among all threads.
Heap is the area in the memory where the objects related to (created in) the program resides and lives. all the objects lives in the heap regardless of its nature and creator (creating and owning thread). It is no matter who(which thread) created the object and whether it is static, non static or method local (any scope). All the objects are stored in the heap until they are collected/claimed by the GC (Garbage Collector).
If you new to java, you might be questioning yourself about what will be treated as object? Every variable reference and assignment that does not belong to any primitive type available (There are eight primitive types) in java can be considered as objects. Therefore any object instantiation including Wrapper classes (Object version of primitive types e.g:- Byte, Short, Long, Float, Character, Integer, Double, Long) will also fall into this category and lives in the heap.Therefore the heap may contain any java object that is created because of the execution of the java application.
In addition the heap stores the static variables (static primitive variables) with the class definition.
Each thread running in the JVM (Java virtual machine) has its own thread stack. This stack is private/local to each thread. The thread stack contains information about which method is currently executed and up-to which line it has been executed to reach the current point of execution. That means that each thread has a pointer into the code which points to the current position of code they’re currently running. This is known as the “call stack“. As the thread executes the code, the call stack may change.
The thread stack also contains all local variables for each method being executed (all methods on the call stack). A thread can only access it’s own thread stack. Local variables created by a thread are only visible to that thread and No other threads can access them.
local variables :- primitive and object reference (not actual objects) variables that are local for the thread including method local variable, instance variable of the class and object variable references.
Even if two threads are executing the exact same code, the two threads will still create the local variables of that code in each their own thread stack. Thus, each thread has its own version of each local variable. . When a thread starts running a new method it saves the arguments and local variables in that method on its own stack. Some of these values might be pointers to objects on the heap. If two threads are running the same method at the same time they will both have their code pointers pointing at that method and have their own copies of arguments and local variables on their stacks. They will only interfere with each other if the things on their stacks point to the same objects on the heap.
All local variables of primitive types (boolean, byte, short, char, int, long, float, double) are fully stored on the thread stack and therefore they are not visible to other threads. One thread may pass a copy of a primitive variable to another thread, but it cannot share the primitive local variable itself.
When the method execution is completed, all the local variables and call stacks will be removed from the memory (stack).
Where the “static” variables are stored ?
Prior to Java 8 (Java 7 and Older versions) static variables are stored in the PermGen (Permanent Generation) space. PermGem space is a special memory area available in the java heap. PermGen space was removed in Java 8 and introduced Metaspace to overcome some limitation of the PermGen space. In Java 8, static variables are stored in the Metaspace.
What is PermGen (Permanent Generation) and Metaspace?
PermGen space is a special memory area available in the JVM heap with Java 7 and older versions. PermGem was used to store meta information about the classes that has been loaded into JVM. In addition, PermGem space is used for storing the static variables of the application. The problem with PermGem space is that it has a fixed max size. Since the PermGen space is a part of Heap, it cannot exceed the allocated memory. Therefore it throws the following error when the it reaches the max PermGem space.
java.lang.OutOfMemoryError: PermGen space
PermGen space was completely removed in Java 8 and Metaspace was introduced as a replacement for the PermGen. Metaspace stores the Class definitions of your Objects, and some other metadata (like static variables).
The main advantage of Metaspace is that it resides in the main memory area of the system (not a part of the Heap) and it does not have a fixed max size. It can increases its size on runtime depending on the available memory of the system. Therefore OutOfMemoryError will not be occurred with Metaspace.
Consider the following code segment.
Student std = new Student();
after executing the above line, JVM memory will be like this.
- Heap: stores “new Student()” (object that has been created)
- Stack: stores information about “std” (reference variable)
- PermGen Space / Metaspace: stores the meta information about Student class
Here is the diagram that illustrates how the objects are stored in the heap, local variables are stored in the stack and method invocations are stored in the call stack.
If the local variable is a primitive type, then it is stored in the Thread Stack,
If the local variable is a reference variable to an object, then the reference variable is stored in the Thread Stack and Object is stored in the Heap.
An object may contain methods and these methods may contain local variables. These local variables are also stored on the thread stack, even if the object belongs to the method, it is stored on the heap. (any object is stored in the heap regardless of its scope)
An object’s member variables (member variables of instance) are stored on the heap along with the object itself. That is true in cases when the member variable is a primitive type or if it is a reference to an object.
static variables (class members) are also stored on the heap (PermGen space or Metaspace) along with the class definition.
Objects on the heap can be accessed by all threads that have a reference to the object. When a thread has access to an object, it can also get access to that object’s member variables. If two threads call a method on the same object at the same time, they will both have access to the object’s member variables, but each thread will have its own copy of the local variables.
Consider the below code examples.
After executing the above example, the heap and stack of the JVM will looks like below (Before running the Garbage Collector) .
There are two threads that execute the MyRunnable instances. run() method will invoke the methodOne(). Then the methodOne() will invoke the methodTwo(). Therefore the call stack for both method should reside in the each Thread stack.
methodOne() declares a primitive local variable (localVariable1) that store a primitive value and object reference variable (localVariable2) that refers the static object (object3) available in the heap. The local primitive variable and object reference will be stored in the local thread stack.
If we look at the MySharedObject class, you can notice that it creates a static object (object3) and two Integer wrapper class objects ( known as object2 and object4). Since all the objects live in the heap, the object3 , object2 and object4 should reside in the heap. In addition, the object3 will have the references for the object2 and object4.
Since the object3 is static, both threads will have the reference for the same object. In other words, both threads will share the object3.
methodOne() will invoke the methodTwo(). if you look at the methodTwo() implementation, you may notice that it creates an Integer wrapper class object which is local to the thread and method. Even if it is local to the thread itself, it is a object creation. Therefore the object should resides in the heap. Since there are two threads running, there should be two another objects available in the heap and each thread stack should have the reference for related object (please see object1 and object5).