- Tech Tutorials
- Tuesday, June 7, 2022
- JVM Run-Time Data Areas — Java Memory Allocation
- The Program Counter (PC) Register
- Java Virtual Machine (JVM) stacks
- Native Method Stacks
- Heap Area
- Method area
- Run-Time Constant Pool
- Java Heap Space vs Stack — Memory Allocation in Java
- Java Heap Space
- Java Stack Memory
- Heap and Stack Memory in Java Program
- Difference between Java Heap Space and Stack Memory
Tech Tutorials
Tutorials and posts about Java, Spring, Hadoop and many more. Java code examples and interview questions. Spring code examples.
Tuesday, June 7, 2022
JVM Run-Time Data Areas — Java Memory Allocation
The Java Virtual Machine (JVM) defines various run-time data areas that are used during the execution of the program. Some of these JVM data areas are created per thread where as others are created on JVM startup and memory area is shared among threads.
As stated above these memory areas can be categorized into two categories-
- Created per thread– PC register, JVM stack, Native method stack
- Shared by threads– Heap, Method area, Run-time constant pool
The Program Counter (PC) Register
In a JVM at any given time many threads may be executing. Each of the executing thread gets its own PC register.
If the method executed by the JVM thread is a JAVA method then the PC register contains the address of the Java Virtual Machine instruction currently being executed. In case, thread is executing a native method, the value of the Java Virtual Machine’s pc register is undefined.
Java Virtual Machine (JVM) stacks
Each JVM thread has its own JVM stack which is created when the thread starts. JVM stack stores frames which are pushed and popped out of stack, a JVM stack is never manipulated directly.
At the time of any exception it is this stack trace you get where each element represents a single stack frame.
- If the computation in a thread requires a larger Java Virtual Machine stack than is permitted, the Java Virtual Machine throws a StackOverflowError.
- If Java Virtual Machine stacks can be dynamically expanded, and expansion is attempted but insufficient memory can be made available to effect the expansion, or if insufficient memory can be made available to create the initial Java Virtual Machine stack for a new thread, the Java Virtual Machine throws an OutOfMemoryError.
A new frame is created when a method is invoked, this frame is then pushed into the JVM stack for the thread. The frame is destroyed when the its method invocation completes.
Each frame has its own array of local variables, its own operand stack and a reference to the run-time constant pool of the class of the current method. The sizes of the local variable array and the operand stack are determined at compile-time and are supplied along with the code for the method associated with the frame.
At any point only one frame is active which is the frame for the executing method. This frame is referred to as the current frame, and its method is known as the current method. The class in which the current method is defined is the current class.
Note that a frame created by a thread is local to that thread and cannot be referenced by any other thread.
- Local Variables— Each frame that is created and added to the JVM stack contains an array of variables known as its local variables.
The length of the local variable array is determined at compile-time itself and supplied in the binary representation of a class or interface along with the code for the method associated with the frame.
The JVM uses local variables to pass parameters when the method is invoked.
If it is a class method, any parameters are passed in consecutive local variables starting from local variable 0.
If it is an instance method, local variable 0 is always used to pass a reference to the object on which the instance method is being invoked i.e. this. Any parameters are subsequently passed in consecutive local variables starting from local variable 1.
Operand stack is the actual storage place at the time of method execution. When the frame is created for the method its operand stack is empty. The Java Virtual Machine will supply instructions to load constants or values from local variables or fields onto the operand stack. Other JVM instructions take operands from the operand stack, operate on them, and push the result back onto the operand stack.
Native Method Stacks
A JVM may also use conventional stacks in order to support native methods. Native methods are the methods written in a language other than the Java programming language.
Native method stacks are allocated per thread when each thread is created.
- If the computation in a thread requires a larger native method stack than is permitted, the Java Virtual Machine throws a StackOverflowError.
- If native method stacks can be dynamically expanded and native method stack expansion is attempted but insufficient memory can be made available, or if insufficient memory can be made available to create the initial native method stack for a new thread, the Java Virtual Machine throws an OutOfMemoryError.
Heap Area
Heap is the JVM run-time data area from which memory is allocated to objects, instance variables and arrays. Heap is created on the JVM start-up and shared among all Java Virtual Machine threads.
Once the object stored on the heap is not having any reference, memory for that object is reclaimed by garbage collector which is an automatic storage management system. Objects are never explicitly deallocated.
- If a computation requires more heap than can be made available by the automatic storage management system, the Java Virtual Machine throws an OutOfMemoryError.
Refer Heap Memory Allocation in Java to know more about Heap memory allocation and how garbage is collected here
Method area
JVM has a method area that is shared among all JVM threads. Method area stores meta data about the loaded classes and interfaces. It stores per-class structures such as the run-time constant pool, field and method data, and the code for methods and constructors.
- Fully qualified name of the class/interface.
- Fully qualified name of any direct superclass.
- Modifier used.
- Fully qualified names of any extended super interfaces.
- Information to distinguish if loaded type is a class or interface.
- Run time constant pool.
- Field information which includes field name, type, modifier.
- Method information which includes method name, modifier, return type, parameters.
- Static (class) variables.
- Method code which contains byte code, local variable size, operand stack size.
- If memory in the method area cannot be made available to satisfy an allocation request, the Java Virtual Machine throws an OutOfMemoryError.
Run-Time Constant Pool
A run time constant pool is a per class or per interface storage of the constant_pool table of the class. Constant_pool contains constants (string literals, numeric literals) which are known at compile-time, it also stores method and field references that must be resolved at run time.
Run-time constant pool is shared among the threads and allocated from the JVM’s method area.
Rather than storing everything in byte code a separate constant pool is maintained for the class and the byte code contains reference to the constant pool. These symbolic reference are translated into concrete method reference through dynamic linking.
As example – Here is a byte code snippet–
0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: aload_0 5: new #2 // class javafx/beans/property/SimpleStringProperty
If you notice here invokespecial operand has a prefix #1, this number (#1) is reference to the constant pool where instance initialization method is stored.
Same way in line 5 new Opcode is followed by number #2. Which means referring to the 2nd index in the constant pool.
The following exceptional condition is associated with the construction of the run-time constant pool for a class or interface:
- When creating a class or interface, if the construction of the run-time constant pool requires more memory than can be made available in the method area of the Java Virtual Machine, the Java Virtual Machine throws an OutOfMemoryError.
That’s all for this topic JVM Run-Time Data Areas — Java Memory Allocation. If you have any doubt or any suggestions to make please drop a comment. Thanks!
Java Heap Space vs Stack — Memory Allocation in Java
While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.
Sometime back I wrote a couple of posts about Java Garbage Collection and Java is Pass by Value. After that I got a lot of emails to explain about Java Heap Space, Java Stack Memory, Memory Allocation in Java and what are the differences between them. You will see a lot of reference to Heap and Stack memory in Java, Java EE books and tutorials but hardly complete explanation of what is heap and stack memory in terms of a program.
Java Heap Space
Java Heap space is used by java runtime to allocate memory to Objects and JRE classes. Whenever we create an object, it’s always created in the Heap space. Garbage Collection runs on the heap memory to free the memory used by objects that don’t have any reference. Any object created in the heap space has global access and can be referenced from anywhere of the application.
Java Stack Memory
Java Stack memory is used for the execution of a thread. They contain method-specific values that are short-lived and references to other objects in the heap that is getting referred from the method. Stack memory is always referenced in LIFO (Last-In-First-Out) order. Whenever a method is invoked, a new block is created in the stack memory for the method to hold local primitive values and reference to other objects in the method. As soon as the method ends, the block becomes unused and becomes available for the next method. Stack memory size is very less compared to Heap memory.
Heap and Stack Memory in Java Program
package com.journaldev.test; public class Memory < public static void main(String[] args) < // Line 1 int i=1; // Line 2 Object obj = new Object(); // Line 3 Memory mem = new Memory(); // Line 4 mem.foo(obj); // Line 5 >// Line 9 private void foo(Object param) < // Line 6 String str = param.toString(); //// Line 7 System.out.println(str); >// Line 8 >
The below image shows the Stack and Heap memory with reference to the above program and how they are being used to store primitive, Objects and reference variables. Let’s go through the steps of the execution of the program.
- As soon as we run the program, it loads all the Runtime classes into the Heap space. When the main() method is found at line 1, Java Runtime creates stack memory to be used by main() method thread.
- We are creating primitive local variable at line 2, so it’s created and stored in the stack memory of main() method.
- Since we are creating an Object in the 3rd line, it’s created in heap memory and stack memory contains the reference for it. A similar process occurs when we create Memory object in the 4th line.
- Now when we call the foo() method in the 5th line, a block in the top of the stack is created to be used by the foo() method. Since Java is pass-by-value, a new reference to Object is created in the foo() stack block in the 6th line.
- A string is created in the 7th line, it goes in the String Pool in the heap space and a reference is created in the foo() stack space for it.
- foo() method is terminated in the 8th line, at this time memory block allocated for foo() in stack becomes free.
- In line 9, main() method terminates and the stack memory created for main() method is destroyed. Also, the program ends at this line, hence Java Runtime frees all the memory and ends the execution of the program.
Difference between Java Heap Space and Stack Memory
Based on the above explanations, we can easily conclude the following differences between Heap and Stack memory.
- Heap memory is used by all the parts of the application whereas stack memory is used only by one thread of execution.
- Whenever an object is created, it’s always stored in the Heap space and stack memory contains the reference to it. Stack memory only contains local primitive variables and reference variables to objects in heap space.
- Objects stored in the heap are globally accessible whereas stack memory can’t be accessed by other threads.
- Memory management in stack is done in LIFO manner whereas it’s more complex in Heap memory because it’s used globally. Heap memory is divided into Young-Generation, Old-Generation etc, more details at Java Garbage Collection.
- Stack memory is short-lived whereas heap memory lives from the start till the end of application execution.
- We can use -Xms and -Xmx JVM option to define the startup size and maximum size of heap memory. We can use -Xss to define the stack memory size.
- When stack memory is full, Java runtime throws java.lang.StackOverFlowError whereas if heap memory is full, it throws java.lang.OutOfMemoryError: Java Heap Space error.
- Stack memory size is very less when compared to Heap memory. Because of simplicity in memory allocation (LIFO), stack memory is very fast when compared to heap memory.
That’s all for Java Heap Space vs Stack Memory in terms of java application, I hope it will clear your doubts regarding memory allocation when any java program is executed.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.