[Java] Java reference mechanism (stack and heap)

4 minute read

I had an opportunity for my juniors to explain the Java reference mechanism using the stack area and Java heap area. I remember I was a bit confused about Java references when I wasn’t aware of the relationships between these areas. This is a good opportunity, so I’ll try to put it together in an article.

Mechanism for realizing Java reference

The JVM has a stack area and a Java heap area to implement Java reference. Java reference is realized by these two areas.

Region name Overview
Stack area Mainly holds reference information to the heap area. It also holds values of primitive type.
JAVA heap area The actual value of the object is stored in this memory.

Difference in the method of holding the value of object and primitive type

Java objects (Class, array, etc.) have heap area reference information in the stack area. The actual value is stored in the heap area. Object reference image

Primitive types have different memory management than objects. When you create a variable of primitive type, the value is held in the stack area.

  • However, since the primitive type array is treated as an object, the value is retained in the heap area. Primitive memory management image.png

Behavior when passing to method argument

When passing an object or variable of primitive type to the method argument The contents of one stack area are copied to another stack area. Behavior when passed as an argument.png In the above case, the reference of argA is the same as the variable a. Changing the referenced value inside method1 also affects variable a.

  • Since argB is a primitive type, it is separated from the variable b.

Source code sample

In order to confirm whether the contents described so far are correct, I will explain by comparing the source code and the output result.

Example 1

source code


package test;

class Class1 {
String id;
int value;
}

public class Test {
public static void main(String[] args) {

Class1 a = new Class1();
a.id = "ID1";
a.value = 1;

// Operation [1]
Class1 b = a;
// Operation [2]
b.id = "ID2";
b.value = 2;

// Operation [3]
b = null;
// What is the value output here?
System.out.println("id:" + a.id);
System.out.println("value:" + a.value);
}
}

[Operation content] Example 1.png

By the operation [2], the reference value of variable a is also rewritten. The reference of the variable b is deleted by the operation [3], but it does not affect the variable a with a different stack. Therefore, the output contents are as follows.

output result


id:ID2
value:2

Example 2

source code


package test;

class Class1 {
String id;
int value;
}

public class Test {
public static void main(String[] args) {

Class1 a = new Class1();
a.id = "ID1";
a.value = 1;

// Operation [1]
method1(a);
// What is the value output here?
System.out.println("id:" + a.id);
System.out.println("value:" + a.value);
}

private static void method1(Class1 argA) {
// Operation [2]
argA.id = "ID2";
argA.value = 2;
}
}

[Operation content] Example 2.png By the operation [2], the reference value of variable a is also rewritten. Therefore, the output contents are as follows.

output result


id:ID2
value:2

Example 3

source code


package test;

class Class1 {
String id;
int value;
}

public class Test {
public static void main(String[] args) {

Class1 a = new Class1();
a.id = "ID1";
a.value = 1;

// Operation [1]
method1(a);
// What is the value output here?
System.out.println("1st time ==========");
System.out.println("id:" + a.id);
System.out.println("value:" + a.value);

// Operation [2]
method2(a);
// What is the value output here?
System.out.println("2nd time ==========");
System.out.println("id:" + a.id);
System.out.println("value:" + a.value);
}

private static void method1(Class1 argA) {
argA = null;
}

private static void method2(Class1 argA) {
argA = new Class1();
argA.id = "ID2";
argA.value = 2;
}
}

[Operation content] The variable a is passed as an argument of the method as in Example 2. The method of operation [1] deletes the reference of argA by assigning null, but it does not affect the variable a whose stack is different. Since the method of operation [2] is newly updating Class1, the reference destination is changed to the variable a. Setting the values for id and value after changing the reference does not affect the variable a. Therefore, the output contents are as follows.

output result


1st time ==========
id:ID1
value:1
Second time ==========
id:ID1
value:1

Example 4

source code


package test;

public class Test {
public static void main(String[] args) {

int a = 1;

// Operation [1]
int b = a;
// Operation [2]
b = 99;

// What is the value output here?
System.out.println("1st time ==========");
System.out.println("a:" + a);
System.out.println("b:" + b);

// Operation [3]
method1(a);

// What is the value output here?
System.out.println("2nd time ==========");
System.out.println("a:" + a);
}

private static void method1(int argA) {
// Operation [4]
argA = 99;
}
}

[Operation content] Screenshots 2020-06-02 0.58.52.png Each primitive type variable holds its value in the stack area independently. Each operation does not affect another variable. Therefore, the output contents are as follows.

output result


1st time ==========
a:1
b:99
Second time ==========
a:1

Example 5

source code


package test;

public class Test {
public static void main(String[] args) {

int a = 0;

// Operation [1]
int[] b = {a};

// Operation [2]
method1(b);

// What is the value output here?
System.out.println("a:" + a);
System.out.println("b[0]:" + b[0]);
}

private static void method1(int[] argB) {
// Operation [3]
argB[0] = 99;
}
}

[Operation content] Example 5.png If you retain an array even for a primitive type, its value will be saved in the heap area. If the operation [3] changes the array argB, it affects the array b that has the same reference destination. Therefore, the output contents are as follows.

output result


a:0
b[0]:99