JVM(Java Virtual Machine)
은 자바 프로그램을 실행시키는 도구다. 즉, JVM은 자바로 작성한 소스 코드를 해석해 실행하는 별도의 프로그램이다.
자바는 JVM을 매개해서 운영체제와 소통한다. 즉, JVM이 자바 프로그램과 운영체제 사이에서 일종의 통역가 역할을 수행한다.
JVM은 각 운영체제에 적합한 버전이 존재한다. 운영체제에 맞게 JVM이 개발되어져 있으며, JVM은 자바 소스 코드를 운영 체제에 맞게 변환해 실행시켜준다. 이것이 자바가 운영체제로부터 독립적으로 동작할 수 있는 이유이다.
스택은 일종의 자료구조다. 자료구조는 프로그램이 데이터를 저장하는 방식으로 스택은 여러 저장 방식 중 하나이다.
스택은 흔히 LIFO라는 키워드로 설명됩니다. LIFO는 “Last In First Out”의 약자로, 마지막에 들어간 데이터가 가장 먼저 나온다는 의미다.
JVM에서 Stack
의 작동
메서드가 호출되면 그 메서드를 위한 공간인 Method Frame이 생성된다. 메서드 내부에서 사용하는 다양한 값들이 있는데 참조변수, 매개변수, 지역변수, 리턴값 및 연산시 일어나는 값들이 임시로 저장된다. 이러한 Method Frame이 Stack에 호출되는 순서대로 쌓이게 되는데, Method의 동작이 완료되면 역순으로 제거된다.
Heap
영역이 존재한다. JVM이 작동되면 이 영역은 자동 생성되며, 이 영역안에 객체나 인스턴스 변수, 배열이 저장된다.Person person = new Person();
위의 예시에서 new Person()
이 실행되면 Heap
영역에 인스턴스가 생성되며, 인스턴스가 생성된 위치의 주소값을 person
에게 할당해주는데, 이 person
은 Stack
영역에 선언된 변수다.
즉, 우리가 객체를 다룬다는 것은 Stack
영역에 저장되어 있는 참조 변수를 통해 Heap
영역에 존재하는 객체를 다룬다는 것이다. 즉, Heap
영역은 실제 객체의 값이 저장되는 공간이다.
Person person = new Person();
person.setName("김코딩");
person = null;
// 가비지 발생
person = new Person();
person.setName("박해커");
예시 첫째 줄에서 참조 변수 person
은 Person
클래스의 인스턴스의 주소값을 할당받고, 이어서 “김코딩”이라는 문자열이 person
이 가리키는 인스턴스의 name
이라는 속성에 할당된다.
그런데, 세 번째 줄에서 참조 변수 person
에 null
이 할당됨으로써, 기존에 person
이 가리키던 인스턴스와 참조변수 person
간의 연결이 끊어졌다.
가비지 컬렉터는 이렇게 아무한테도 참조되고 있지 않은 객체 및 변수들을 검색하여 메모리에서 점유를 해제하며, 그럼으로써 메모리 공간을 확보하여 효율적으로 메모리를 사용할 수 있게 한다.
JVM의 Heap
영역은 객체는 대부분 일회성이며, 메모리에 남아 있는 기간이 대부분 짧다는 전제로 설계되어 있다. 객체가 얼마나 살아있느냐에 따라서 Heap
영역 안에서도 영역을 나누게 되는데 Young, Old영역 2가지로 나뉜다.
Young 영역 : 새롭게 생성된 객체가 할당되는 곳이고 여기에는 많은 객체가 생성되었다 사라지는 것을 반복한다. 이 영역에서 활동하는 가비지 컬렉터를 Minor GC
라고 부른다.
Old 영역 : Young영역에서 상태를 유지하고 살아남은 객체들이 복사되는 곳으로 보통 Young 영역보다 크게 할당되고 크기가 큰 만큼 가비지는 적게 발생한다. 이 영역에서 활동하는 가비지 컬렉터를 Major GC
라고 부른다.
기본적으로 가비지 컬렉션이 실행될 때 따르는 2가지 단계
Stop The World
는 가비지 컬렉션을 실행시키기 위해 JVM이 애플리케이션의 실행을 멈추는 작업이다. 가비지 컬렉션이 실행될때 가비지 컬렉션을 실행하는 스레드를 제외한 모든 스레드들의 작업은 중단되고, 가비지 정리가 완료되면 재개된다.
Mark
는 사용되는 메모리와 사용하지 않는 메모리를 식별하는 작업을 의미하며, Sweep
은 Mark단계에서 사용되지 않으므로 식별된 메모리를 해제하는 작업을 의미한다.
Stop The World를 통해 모든 작업이 중단되면, 가비지 컬렉션이 모든 변수와 객체를 탐색해서 각각 어떤 객체를 참고하고 있는지 확인한다. 이후, 사용되고 있는 메모리를 식별해서(Mark) 사용되지 않는 메모리는 제거(Sweep)하는 과정을 진행한다.