Java code comprise of class and variable. Class and Variable come with different scope(private/public/static). All this takes memory. JVM has been given responsibility to run the java code. JVM gives memory for class/variables.
But how does JVM manages memory?
Let’s imagine JVM memory as big box as it is shown in the picture below. We will try to fit the different part of it as we go forward.
Let’s suppose our application for which JVM memory is shown is an e-commerce shopping site. Three users are simultaneously logged in on the shopping site. Our JVM will be supporting three different users in three different threads. Let’s say user-1 is browsing mobile phone section and user-2 is browsing cloth section. What user-1 is browsing should not be known to user-2 and vice versa. That requires some memory area which should be allocated on per thread basis. On the other hand, we have data like class instances which can be used by all threads and that requires a common memory area.
Memory areas which are allocated per thread are created when thread is created and the memory area is destroyed when thread exits. In the context of our story, as soon as one of the three users closes the shopping site, his data should be erased as it is not needed. Memory which are allocated common for all threads are created when JVM starts, i.e. when program starts running and are destroyed when JVM ends.
Let’s look at different areas one by one:
The PC register
Since JVM supports many thread. Program Counter or PC register holds the address of JVM instruction currently being executed for any particular thread. An example of JVM instruction is d2f which converts a double value to float value. If the current method being executed is not one of JVM instruction set, it has to be a native method. In case of native methods, the value of the Java Virtual Machine’s pc register is undefined. PC register is sort of manager who knows what the thread is doing. As it must be evident by now, PC register is for every thread. Let’s update that in our memory area.
Java Virtual Machine Stacks
Any thread has sequence of methods to invoke. That sequence of methods, along with the local variables and the partial result is stored in Frame. Java Virtual Machine Stack stores such frames. The memory for a Java Virtual Machine stack does not need to be contiguous. You may specify the size of JVM stack using -xss parameter.
java -Xss4m Test
If computation of a thread requires more memory than what we have permitted (4 MB in the example here), our program will throw Stack Overflow Exception. If we are creating new thread, but we don’t have enough memory to give JVM stack to the new thread, the program will throw Out Of Memory Exception. Out of Memory Exception will also be thrown if our JVM Stacks can dynamically increase its size but we don’t have memory to increase it’s size. It should be evident by now that JVM stacks are created per thread. Now that we know this, can we update our memory diagram?
Native Method Stacks
Native methods are methods written in a language other than the Java programming language. It can be C, C++ or any other programming language.Native method stacks are typically allocated per thread when each thread is created. Native method stacks either to be of a fixed size or to dynamically expand and contract as required by the computation. If we are creating new thread, but we don’t have enough memory to give Native method stacks to the new thread, the program will throw Out Of Memory Exception. Out of Memory Exception will also be thrown if our Native method stacks can dynamically increase its size but we don’t have memory to increase it’s size. Let’s update our memory diagram.
The Java Virtual Machine has a heap that is shared among all Java Virtual Machine threads. The heap is the run-time data area from which memory for all class instances and arrays is allocated. The heap is created on virtual machine start-up. Heap storage for objects is reclaimed by Garbage Collector. Whenever we create any object in our program, the object is created in heap and the stack(JVM/Native) stores the reference to it. The primitive type data like int, char are created in stack space. We can use -Xms and -Xmx JVM option to define the startup size and maximum size of heap memory. if heap memory is full, it throws Out Of Memory Exception. The data stored in heap is not thread safe. Now, our memory diagram looks like this:
The Java Virtual Machine has a method area that is shared among all Java Virtual Machine threads. You may think that this area stores all the compiled code. It stores per-class structures such as the run-time constant pool, field and method data, and the code for methods and constructors. If memory in the method area cannot be made available to satisfy an allocation request, the Java Virtual Machine throws an OutOfMemoryError. Let’s see the memory diagram.
Run-Time Constant Pool
Assume this area as symbol table. This area is inside the method area. Here, the compiled class generated something of the sort of symbol table. This symbol table is then referenced by the frames in stacks.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.
Now, that we have described each part of the JVM memory. Let’s see the final memory diagram.
By the way, what happens in the case when user-4 comes? Do we have enough memory to accommodate him?
If you liked this article and would like one such blog to land in your inbox every week, consider subscribing to our newsletter: https://skillcaptain.substack.com