자바 메모리 구조에서는 Heap과 Stack은 짝꿍으로 붙어다니는데 코드를 실행 시키면 Heap과 Stack 어떻게 동작하는지 알아보자.
각 특징에 대해서는 메모리 구조에 설명했으니 코드 중심으로 작성하겠다.
가장 먼저 딱 두가지만 복습해보자.
- Heap은 동적으로 생성되는 객체가 저장되는 곳이다.
- Stack은 Primitive type의 값을 저장하거나, Heap에서 생성된 객체의 주소를 참조한다.
public class Memory {
public static void main(String[] args) {
int num = 3;
String str = "newJeans";
}
}
먼저 간단하게 Primitive type과 Referece type 객체 하나씩 만들었다. 이건 어떻게 메모리에 들어갈까?
먼저
Stack에 Primitive type의 변수는 값과 함께 저장되고 String객체가 생성 되면서 Heap에 String객체 "newJeans"이 생성되고 이 주소를 Stack에 str변수가 참조하게 된다.
public class Memory {
public static void main(String[] args) {
List<Integer> intList = new ArrayList<>();
intList.add(1);
intList.add(2);
print(intList);
}
public static void print(List<Integer> list){
Integer val = 3;
list.add(val);
System.out.println(list);
}
}
복잡해 보일 수 있지만 main메서드 부터 순서대로 따라가면 볼만하다.
List<Integer> intList = new ArrayList<>(); : Heap에 List 객체를 만들고 Stack inList가 참조함.
intList.add(1) : Heap에 Integer객체 1을 만들고 intList가 참조하고 있는 List객체 0번이 참조함.
intList.add(2) : Heap에 Integer객체 2을 만들고 intList가 참조하고 있는 List객체 1번이 참조함.
print(intList) : print메서드 매게변수 list도 intList가 참조하고 있는 List객체 참조.
Integer val = 3 : Heap에 Integer객체 3만들고 print 메서드 지역변수 val이 참조함.
list.add(val) : val이 참조하고 있는 Integer 객체 3을 Heap의 List가 참조함.
public class Memory {
public static void main(String[] args) {
String str = "Pass By Referece";
strAdd(str);
System.out.println(str); // 맞춰보세요!
}
public static void strAdd(String s){
s = s + " 참조 값이 넘어와요";
System.out.println(s); // Pass By Referece 참조 값이 넘어와요
}
}
메모리가 지워지는 과정을 보기전에 위 코드의
System.out.println(str);부분에 뭐가 나올지 생각해보자. Referece Type은Pass By Referece로 값을 전달한다고 하는데 str값이 변하지 않은걸 볼 수 있다.
이유는 String객체는 불변성이 있어서 그렇다. String 뿐아니라Wrapper Class는 모두 불변성이 있으니 알아두는게 좋다.
그림으로 확인해보자.
이 그림은 strAdd(str)메서드 실행까지의 메모리 구조다. 이젠 이정도는 유주 할 수 있으리라 믿는다. 그럼 매개변수 s의 연산을 해보자!
불변성이 있는 String객체의 연산은 새로운 객체를 만들어 참조하게 하는 형태다. 때문에 Heap에
Pass By Referece 참조 값이 넘어와요라는 새로운 String 객체가 만들어지고 s는 새로운 객체를 참조하게 된다. 이제 strAdd()메서드가 끝이 났다 메모리는 어떻게 될까?
strAdd()메서드가 종료되면서 Stack에 s변수가 pop되어 사라지고, s변수가 참조하고 있던 String 객체는 참조가 끊겨 버린다. Heap영역에 참조가 없는 객체를
Unreachable객체라고 하는데 GC는 Heap영역에 참조가 안된 객체를 지워버려서 메모리 공간을 확보한다.
한 줄평 : 무지성이라... 이정도 이해하는것도 쉽지가 않았다.
참고 - 여기는 반드시 들어가보는걸 추천합니다.
https://yaboong.github.io/java/2018/05/26/java-memory-management/