JVM
자바 프로그램은 운영체제에서 바로 실행할 수 없다. 왜냐하면 자바 프로그램은 완전한 기계어가 아닌, 중간 단계의 바이트 코드이기 때문에 이것을 해석하고 실행하는 중간다리가 필요하다. 이 역할을 하는 것이 JVM이다.
- JVM은 자바 프로그램을 실행시키는 도구로써, 자바로 작성한 소스 코드를 해석해 실행하는 별도의 프로그램이다.
- 자바는 c언어와 달리 JVM을 매개해서 운영체제와 소통한다.
위 사진을 참고하면 각 운영체제 별로 JVM이 개발되어져 있다. 따라서, 운영체제로부터 독립적으로 동작이 가능하다.
JVM 내부구조
- 소스 코드를 작성하고 실행하면, 컴파일러가 실행되면서 컴파일이 진행된다.
- 컴파일의 결과로 .java 확장자를 가졌던 자바 소스 코드가 .class 확장자를 가진 바이트 코드 파일로 변환
- JVM은 운영 체제로부터 소스 코드 실행에 필요한 메모리를 할당받는다. -> 런타임 데이터 영역
- 클래스 로더가 바이트 코드 파일을 JVM 내부로 불러들여 런타임 데이터 영역에 적재시킴
- 로드가 완료되면 실행엔진이 런타임 데이터 영역에 적재된 바이트 코드를 실행시킴
- 실행엔진은 두 가지 방식으로 바이트 코드를 실행
- 인터프리터를 통해 코드를 한 줄씩 기계어로 번역하고 실행
- JIT 컴파일러를 통해 바이트 코드 전체를 기계어로 번역하고 실행
JVM 메모리 구조
- JVM이 java 프로그램이 로드되어 실행될 때 특정 값 및 바이트코드, 객체, 변수 등과 같은 데이터들이 메모리에 저장되어야 한다.
- 런타임 데이터 영역이 바로 이러한 정보를 담는 메모리 영역이며, 크게 5가지 영역으로 구분되어 있다.
각각의 영역에 대해 알아보자
Stack 영역이란
스택은 일종의 자료구조이다. 자료구조는 프로그램이 데이터를 저장하는 방식을 의미한다.
스택은 LIFO라는 키워드로 설명되는데 간단히 설명하자면, 위가 뚫린 원통 모양의 통이 있다고 가정하고, 데이터가 순차적으로 이 원통에 들어가게 되고, 데이터를 꺼내게 될 때에는 가장 마지막에 들어온 데이터가 나가게 된다. 다시 말해 선인후출 방식으로 동작이 된다.
JVM 안에서 스택은 어떻게 동작하는지 알아보자.
메서드가 호출되면 그 메서드를 위한 공간인 Method Frame이 생성된다.
- Method Frame은 호출되는 순서대로 스택에 쌓이게 된다.
- Method의 동작이 완료되면 역순으로 제거된다.
Heap 영역
- JVM에는 단 하나의 Heap 영역이 존재한다
- JVM이 작동되면 이 영역은 자동 생성된다.
- 이 영역안에 객체나 인스턴스 변수,배열이 저장된다.
heap 영역과 stack 영역의 관계를 예시로 들어보면
Person person = new Person();
위 코드처럼 인스턴스를 생성할 때에 메모리 동작은
- new Person() 이 실행되면, Heap 영역에 인스턴스가 생성된다.
- 인스턴스가 생성된 위치의 주소값을 person에게 할당해준다. 이 person은 stack 영역에 선언된 변수이다.
우리가 객체를 다룬다는 것은 Stack 영역에 저장되어 있는 참조 변수를 통해 Heap 영역의 인스턴스를 다룬다는 의미이다. Heap 영역은 실제 객체의 값이 저장되는 공간이다.
메서드 영역
- JVM이 시작될 때 생성되는 공간으로 바이트 코드(.class)를 처음 메모리 공간에 올릴 때 초기화되는 대상을 저장하기 위한 메모리 공간
- JVM이 동작하고 클래스가 로드될 때 적재되서 프로그램이 종료때 까지 저장된다.
- Static 영역이라고도 하며 전역 변수와 정적 멤버변수가 저장되는 영역이다.
- 패키지나 클래스 정보가 올라간다.
Native Method Stack 영역
- 일반적으로 JVM은 네이티브 방식을 지원
- 스레드에서 네이티브 방식의 메소드가 실행되는 경우 Native Method Stack 에 쌓이게 된다.
- 네이티브 메소드란? : 자바가 아닌 다른 언어로 구현된 메소드이다.
- 네이티브 메소드의 앞에는
native
키워드가 붙어있다.
- 예로 현재 스레드를 가져오는
Thread.currentThread()
메소드가 있다.
- 일반적인 메서드를 실행하는 경우 JVM 스택에 쌓이다가 해당 메소드 내부에 네이티브 방식을 사용하는 메소드 Ex) c언어로 작성된 메소드가 있으면 해당 메소드는 네이티브 스택에 쌓인다.
PC Register
- PC Register은 스레드가 생성될 때마다 생성되는 공간
- 현재 수행중인 JVM의 명령어 주소를 가지고 있다.
- JVM은 CPU에 직접 명령을 수행하지 않는다
- 스택 프레임에 있는 Operande 스택 영역에서 명령어를 뽑아내어 PC Register라는 별도의 메모리 공간에 저장한 후 CPU에 명령을 전달한다.
- JVM이 스택 기반의 PC Register을 사용하는 목적은, JVM은 플랫폼에 독립적으로 동작하기 위함이다.
Garbage Collection
Garbage Collection 이란?
- 자바에서는 가비지 컬렉션이라는 메모리를 자동으로 관리하는 프로세스가 포함되어 있다.
- 프로그램에서 더 이상 사용하지 않는 객체를 찾아 삭제하거나 제거하여 메모리르 확보하는 것을 의미
아래의 예시로 알아보면
Person person = new Person();
person.setName("김코딩");
person = null;
// 가비지 발생
person = new Person();
person.setName("박해커");
- 첫째 줄에서 person은 Person 클래스의 인스턴스 주소값을 할당받고, "김코딩" 이라는 문자열이 person이 가리키는 인스턴스의 name이라는 속성에 할당된다.
- 그런데, 셋째 줄에서 person에 null이 할당되어 기존에 person이 가리키던 인스턴스와 참조변수 person간의 연결이 끊겼다.
- 프로글매이 실행 중일 때 이처럼 아무도 인스턴스를 참조하지 않으면, person이 가리키던 인스턴스가 존재해야 할 이유가 없다.
- 가비지 컬렉션은 아무도 참조하지 않는 객체 및 변수들을 검색해서 메모리에서 점유를 해제한다. 즉, 효율적인 메모리 관리가 가능해진다.
동작방식
-
JVM의 Heap 영역은 객체는 대부분 일회성, 메모리에 남아 있는 기간이 대부분 짧다는 전제로 설계되어 있다.
-
얼마나 살아있냐에 따라 Heap 영역에서도 영역을 나누게 된다.
- Young , Old 영역으로 나뉜다
-
Young 영역에서는 새롭게 생성된 객체가 할당되는 곳으로 여기에는 많은 객체가 생성되었다 사라지는 것을 반복 ( Minor GC)
-
Old 영역에서는 Young 영역에서 상태를 유지하고 살아남은 객체들이 복사되는 곳으로 보통 Young 영역보다 크게 할당되고 크기가 큰 만큼 가비지는 적게 발생한다. (Major GC)
- Young 영역과 Old 영역은 서로 다른 메모리 구조로 되어 있어, 세부적인 동작 방식이 다르다.
- 기본적으로 가비지 컬렉션이 실행될 때는 다음의 2가지 단계를 따른다.
- Stop The World :
- 가비지 컬렉션을 실행시키기 위해 JVM이 애플리케이션의 실행을 멈추는 작업
- 가비지 컬렉션이 실행될 때 가비지 컬렉션을 실행하는 스레드를 제외한 모든 스레드들의 작업은 중단되고, 가비지가 정리가 완료되면 재개된다.
- Mark and Sweep
- Mark는 사용되는 메모리와 사용하지 않는 메모리를 식별하는 작업
- Sweep은 Mark 단계에서 사용되지 않음으로 식별된 메모리를 해제하는 작업을 의미
🎓Reference
JVM
메서드 영역
Native Method Stack 영역
Native Method
PC Register