Java memory allocation

In the previous posts, which you can find here  and here, I introduced both the stack and the heap. But what exactly are these memory spaces for? How do they work together and help me as a developer? Oh and I am going to talk about references as well. Pass by value, pass by reference… let’s clear the air on those subjects!

What was the stack again?

The stack in short:  it’s a java managed memory space, implemented as a LiFo data structure where you can only “push” and “pop” items. Pushing is adding items. When you add an item. the previous item gets pushed down. ‘Popping’ is removing an item, but you can only remove the top item. So logically, the last item that is pushed will be the first item that will be popped.

The stack holds all the java variables in a method (not the objects, but the variables that hold the references), all the local primitives and also all the parameters that are passed into a method. All of these are stored in frames. Simply said, a frame is a chunk of memory created and pushed on the stack whenever a new method is called. It is destroyed when that method has reached its end.

Also important to remember: there is a stack for every thread. A new stack is created whenever you create a new thread.

And the heap?

The heap is also a java managed memory space but it is created when the JVM is started. Unlike the stack, there is only one, but it is divided in multiple parts. Read the previous post on the heap if you are curious about the what and the why of those smaller parts. This memory space holds all of the actual objects and arrays.

Basic memory allocation

In order to explain this in a way that is understandable, we need code. Lets consider the following :

 

A basic class with a main method

This is straightforward code, very simple. No rocket science here. We have a class called test with only a main method. Now lets suppose the program runs and the the main method is invoked. What happens on the stack?

line 1: the main method is invoked

So when the main method is invoked, a new frame is created and pushed to the top of the stack. This frame, the top frame is also called the current frame. Since there can only be 1 frame at the top at any given time, there can be only one current frame. It is represented by the orange block. In that frame, the parameter ‘args’ is added. This parameter is a reference type (an array). This means that the variable itself holds a reference to an object, not the object itself. And this is the whole point of the stack: it holds variables which can have primitive values or references (yes indeed, #12354 is just my way to indicate a reference). So then where is this array stored? In the heap of course! But more on that in the next paragraph. Lets first see what happens when the rest of the code is ran.

line 2 is executed

The program creates a new variable on line 2. There is no new frame created, as frames are only created when a method is invoked. Java stores this new variable age in the current frame. In the picture I have put the new variable on top of the previous one, but this is just for representational purposes. In the current frame, there space reserved for different kinds of data and the new variable is going to be placed in such a space. That is the important thing to know. Since the variable ‘age’ is of a primitive type, its real value gets stored in the stack as well. This is very important to understand: for primitives, the value gets stored in the stack.

When the code hits line 3, pretty much the same thing happens. A new variable gets added to the current frame with its given value. When the method reaches its end, the current frame is removed (popped) from the stack and in this example, the stack becomes empty again.

When the method ends, the current frame is removed

Allocating reference types

The previous example was pretty basic. We did however had a reference type as a parameter. Where is this object, referred by the variable ‘args’ stored? Lets revisit the example code, but with a few extra lines added to it.

The ‘args’ parameter in the main method holds a reference to an object. In this case, its a String array. The next line to be executed will create a new object of the type Animal.

There is a couple of things happening now. A new variable with the name lion is added to the current frame. A new object is created of the type Animal. This object is stored on the heap and then the value of the reference is stored in the variable called ‘lion’. Pretty simple right?

More method invocations

Lets spice things up a bit. In the next example there is an extra method call in the main method. Consider the picture below. The situation depicted should be familiar.

We know how we got here, right? The following figure shows what happens when the next line, which is a method invocation, is executed.

As you can see, a new frame is pushed onto the stack, because we started a new method. This means that the previous frame, the one with the args and the lion variables, is no longer the current frame. This makes sense, as we are no longer the main method, we are in the ‘printName’ method. You could say that the previous frame is… out of scope! This means that the variables ‘args’ and ‘lion’ are no longer directly usable. Note however that their references are still there!

On the heap, a new object of type String is created. The String type is a special java type, as it can construct new objects without the need to call the constructor. Using the quotations as we did when invoking the method ‘printName’ is a shortcut for creating a new String. The parameter ‘name’ is put into the current frame and it holds the reference to the newly made String object.

By now, you should already be able to predict what happens on the stack and heap when the next line is of the ‘printName’ method is executed.

A new primitive variable is being made. This means that on the heap nothing changes. On the stack, a new variable ‘age’ is added with its value. After that, the ‘System.out.println’ method is invoked. I will not go deeper into that ‘println’ method as by now you have pretty good idea already on what is going under the hood.

When the method finishes, the current frame is popped from the stack and the previous frame becomes the current frame. The ‘name’ parameter and the ‘age’ variable are now out of scope and the reference held by the name parameter to the String object in the heap is gone. This means that this String object is now eligible for garbage collection.

The variables from the main method are now back in scope as the frame created by this method is now again the current frame.

Instance variables and static fields

Consider the code in the following picture. Execution of the main method has begun and the state of the stack and the heap is something we are familiar with by now.

The class Animal has as static field and a class level field. Static fields are on class level. This means that the field or variable is created when the class is loaded. When an instance is made of a class with a static field, that field will not be created again for that instance. It is bound to  the class. Instead it is shared with all the objects of that class. 

So what exactly happens when the next line of code is executed? Let’s have a look.

First, a new object of type Animal is created. This means that the class Animal is being loaded in the JVM. We know that all of the metadata of a class in java memory is stored in either the PermGen space or in the Metaspace depending on which version of java you are using. Both memory spaces hold the static references of classes. This means that the reference and the variable is stored in the PermGen space or in the Metaspace but the object to which the reference is pointing to, resides in the heap. In the case of a static primitive variable, both the variable and its value are stored in either the PermGen space or Metaspace.  More info on static variables can be found here.

The class ‘Animal’ is loaded, which creates a new object of type String in the heap. The class ‘Animal’ also has an instance variable which is called ‘parent’. This variable however does not reside on the stack. It is part of ‘parent’ object and it is stored with the object on the heap. When the parent object is instantiated, a new ‘animal’ object is created on the heap. The variable ‘parent’ then holds the reference to that object as its value.