JVM(Java Virtual Machine)
자바 가상 머신 JVM(Java Virtual Machine)은 자바 프로그램 실행환경을 만들어 주는 소프트웨어입니다.
- OS에 종속받지 않고 CPU가 Java를 인식하고 실행할 수 있게 하는 가상 컴퓨터라고 말합니다.
Java Compiler가 .java 파일을 .class 파일 즉, 바이트 코드(JVM이 이해하는 명령어 집합)로 만들면 이 코드가 자바 가상 머신 환경에서 실행되면서 OS에 종속받지 않게 됩니다.
- 언어 마다 사용할 수 있는 방법은 다르겠지만 Java 뿐만 아니라 .class 파일을 통해서 JVM를 사용하는 언어들이 있습니다.
- Java Compiler의 javac 명령을 통해서 .class 파일을 생성할 수 있습니다.
- .class 파일을 java <.class 파일 이름>을 이용해서 JVM을 실행시킬 수 있습니다.
JVM?? 벤더 중에서 선택해서 JDK만 설치했는데??
JDK(Java Development Kit)에는 Java언어를 통해서 개발자가 프로그래밍시 필요한 도구(컴파일러 등)를 포함해서 들어있습니다.
- JDK를 설치해야 내가 작성한 자바를 컴파일해서 .class파일을 만들고 JVM에게 보내줄 수 있겠네요!
JRE(Java Runtime Enviroment)는 컴파일된 자바 프로그램을 현재 사용하는 컴퓨터의 운영체제에 맞게 실행시킬 수 있는 자바 환경으로 JVM이 자바 프로그램을 동작시킬 때 필요한 라이브러리 파일들을 가지고 있습니다. (JVM 구현체)
- JRE는 JVM의 실행환경을 제공하기 때문에 바이트코드를 JVM이 읽어와서 OS에 종속받지 않게 하려면 JRE를 반드시 설치해야 한다고 말할 수 있습니다.
JRE에는 자바 프로그래밍 도구(컴파일러 등)이 포함되어 있지 않기 때문에 자바를 프로그래밍을 할 수 없는데 JDK 안에는 JRE와 프로그래밍 도구(컴파일러 등)가 있기 때문에 우리는 지금까지 JDK만 설치해서 Java를 사용할 수 있었습니다.
- Java는 플랫폼(운영체제)에 종속적이지 않지만 JVM은 플랫폼에 종속적이라고 하는 말도 JRE를 설치할 때 운영체제에 맞는 환경을 설치해야 하기 때문이라고 생각할 수 있습니다.
JVM 구조
Class loader System
.class 파일에서 Class 안에 필드와 메소드 정보 그리고 바이트코드까지 포함해서 클래스에 모든 정보를 읽어서 .class 파일을 메소드 영역에 올려줍니다.
로딩
클래스 로더가 .class 파일을 읽고 그 내용에 따라 적절한 바이너리 데이터를 만들고 Method 영역에 저장한다.
3가지의 클래스 로더가 존재하며 Bootstrap(최상위 부모) ➡️ Extension(자식) ➡️ Application(하위 자식) 순서로 찾게 된다.
- class를 찾지 못하면 ClassNotFoundException이 발생하게 된다.
링크
Verify: 바이트 코드가 수정되었을 수 있기 때문에 .class 파일 형식이 유효한지 체크한다.
Prepare: 클래스 변수(static 변수)와 기본값에 필요한 메모리를 준비한다.
Resolve: 심볼릭 메모리 레퍼런스(바이트 코드에서 객체 참조시 실제 레퍼런스를 가르키고 있지 않고 논리적인 레퍼런스)를 메소드 영역에 있는 실제 레퍼런스로 교체한다.
초기화
링크-Prepare 과정에서 준비한 메모리 영역에 static한 변수의 값을 할당하는 과정을 말한다.
Runtime Data Areas
JVM이 사용하는 메모리 공간
초록색 영역 - 모든 스레드가 공유하는 영역으로 멀티 스레드 프로그래밍을 할 때 동기화에 주의해야 하는 영역이다.
아래 코드를 javac 명령으로 .class 파일을 만들고
javap -v Goorm.class명령을 수행해서 클래스 파일에 정보를 역어셈블을 해보면
- 클래스 파일에는 클래스 파일에 버전정보, 접근제어자, super class, 선언된 필드와 메서드등 해당 클래스에 대한 모든 정보가 담겨 있다.
- 빨간색은 Constant Pool, 파란색은 Bytecde
Constant Pool
클래스 내에서 사용되는 상수들을 담은 테이블
- 왼쪽은 index와 type의 정보 오른쪽은 mapping된 value를 뜻한다.
8번 인덱스에는 com/example/test1/Player라는 값이 담겨 있다.
- Utf8의 타입에서 FQCN(Fully Qualified Class Name)를 문자열로 담고 있다.
FQCN은 클래스가 속한 패키지명을 모두 포함한 이름을 말한다.
- 참조하는 대상의 이름만을 지칭하는 것을 Symbolic Reference라고 한다. 메소드 영역에서 이 값이 Player 클래스의 데이터를 가리키는 포인터로 변하게 된다.
- 12번 인덱스를 보면 Goorm 클래스의 main 메서드 마지막에 Player 클래스의 study 메서드를 호출했었는데 이 정보도 들어 있는 것을 알 수 있다.
메소드 영역 - 클래스의 대한 모든 정보가 저장되어 있는 영역
java 명령어를 통해서 Goorm 클래스를 실행하면 JVM은 Class Path를 탐색하면서 클래스 로더가 Goorm.class 파일을 읽어오고 해당 클래스 정보를 메소드 영역에 올리고 JVM은 메소드 영역에 저장된 바이트코드를 해석한다.
- Constant Pool과 Bytecode가 저장된다.
JVM은 Constant Pool에 대한 포인터를 유지시키는데 해당 클래스가 필요할 때 동적으로 클래스 정보를 로드한다.
Goorm 클래스의 main 문에서 처음 new Player()를 통해서 Player 인스턴스를 만들었다.
- 위에 바이트 코드와 Constant Pool을 보면서 이해해보자
바이트코드 0: 를 보면 new 하고 #7로 되어있는 것을 볼 수 있다.
- Constant Pool에 대한 포인터 #7 인덱스를 보면 값이 #8이고 #8 인덱스의 값은 Player에 Symbolic Reference인 것을 알 수 있다.
- 이 때 Player라는 클래스가 Method 영역에 로드되지 않으면 클래스 로더에게 요청을 보내서 해당 클래스를 메모리에 load하도록 한다.
Player 클래스가 메모리에 로드가 완료되면 Constant Pool #8번에 Symbolic Reference를 Player 클래스의 데이터를 직접 가리키는 reference로 바꾸게 된다.
- Symbolic Reference를 reference로 바꾸는 것을 Constant Pool Resolution이라고 한다.
Heap
Run time에 생성되는 모든 객체들이 저장되어 있다. (GC의 주요 영역)
- JVM은 항상 메소드 영역에 저장된 클래스 정보를 보고 객체를 식별하는데 필요한 메모리 크기를 결정할 수 있다. (필요한 정보들이 메소드 영역에 들어있기 때문)
- JVM이 객체를 위해 필요한 Heap 공간의 크기를 결정 하고 나면 Heap 공간을 할당하고 인스턴스 변수값을 초기값으로 초기화한다.
빨간색 영역 - 스레드가 생성될 때 같이 생성되는 영역으로 서로 다른 스레드가 침범할 수 없는 영역이다.
JVM Stacks
메서드를 실행하기 위한 정보들이 저장되는 공간 으로 Frame 이라는 자료 구조를 사용한다.
- 메서드가 하나 호출될 때마다 새로 생기고 메서드가 끝나거나 예외가 발생하면 사라지게 된다.
- 정수 값이 아니라 객체라면 힙에 저장된 객체 참조값을 Local Variables Array에서 사용하게 된다.
PC(program counter) Registers
현재 실행되고 있는 명령어의 주소를 저장하고 있다.
- 멀티 스레드 환경에서 한 스레드가 작업을 하다가 타이머, 인터럽트등으로 다른 스레드에게 CPU 점유를 넘겨주고 다시 돌아왔을 때 이전에 어떤 명령을 수행하고 있었는지 기억하고 있어야 이전 작업을 다시 수행할 수 있기 떄문에 필요하다.
Native Method Stacks
C나 C++로 작성된 메서드를 실행하는데 사용하는 스택이다.
Runtime Data Area에서 스레드
각 스레드는 Heap과 Method 영역에 접근할 수 있고 하나의 스레드는 다른 스레드의 stack, PC Register, Native Method Stack에 접근할 수 없다. (지역 변수의 동시성 문제를 걱정하지 않아도 되는 이유)
Native Method
native 키워드가 붙은 JNI(Java Native Interface)를 통해서 Native 언어(C/C++, 어셈블리)로 작성된 Native Method Library를 사용할 수 있다.
실행 엔진
인터프리터
바이트 코드를 한줄씩 실행하면서 네이티브 코드(인스트럭션으로 이해함)로 컴파일하는 것입니다.
JIT 컴파일러(Just-In-Time compiler)
인터프리터 효율을 높이기 위해, 인터프리터가 반복되는 코드를 발견하면 JIT컴파일러로 반복되는 코드를 모두 네이티브 코드로 바꾼다.
- 인터프리터가 해당하는 라인을 보면 이거를 인터프리팅 하는게 아니라 바로 바뀐 네이티브 코드로 컴파일된 코드를 사용하게 된다.
네이티브 코드(컴파일된 코드)는 캐시에 보관하기 때문에 한 번 컴파일된 코드는 빠르게 수행하게 되고 이후에 수정된 코드만 컴파일 한다.
- JIT 컴파일러가 컴파일하는 과정은 바이트 코드를 인터프리팅하는 것보다 훨씬 오래 걸리기 때문에 한 번만 실행되는 코드라면 컴파일 하지 않고 인터프리팅하는 것이 유리하다.
- JIT 컴파일러를 사용하는 JVM들은 내부적으로 해당 메서드가 얼마나 자주 수행되는지 체크하고 일정 정도를 넘을 때만 컴파일을 수행한다.
- JIT 컴파일러는 운영체제에 맞게 바이트 실행 코드로 한 번에 변환하여 실행하기 때문에 이전의 자바 해석기(Java interpreter) 방식보다 성능이 10배 ~ 20배 정도 더 좋다.
GC(Garbage Collector)
더이상 참조되지 않는 객체를 모아서 정리합니다.
더 자바, 코드를 조작하는 다양한 방법 강의 - 인프런
여러분이 사용하고 있는 많은 자바 라이브러리와 프레임워크가 "어떻게" 이런 기능을 제공할 지 궁금한적 있으신가요? 이번 강좌를 통해 자바가 제공하는 다양한 코드 또는 객체를 조작하는 방
www.inflearn.com
[JAVA] JVM이란? 개념 및 구조 (JDK, JRE, JIT, 가비지 콜렉터...)
JVM이란 무엇인가 Java Virtual Machine의 줄임말. 직역하면 '자바를 실행하기 위한 가상 기계(컴퓨터)'라고 할 수 있다. Java 는 OS에 종속적이지 않다는 특징을 가지고 있다. OS에 종속받지 않고 실행되
doozi0316.tistory.com
[Java] 자바 가상머신 JVM(Java Virtual Machine) 총정리
JVM(Java Virtual Machine)이란? 자바 가상 머신 JVM(Java Virtual Machine)은 자바 프로그램 실행환경을 만들어 주는 소프트웨어입니다. 자바 코드를 컴파일하여 .class 바이트 코드로 만들면 이 코드가 자바 가
coding-factory.tistory.com
'Java' 카테고리의 다른 글
default 메서드에서 왜 Obejct 메서드를 재정의하지 못할까? (0) | 2024.04.02 |
---|---|
Enum에서 어떻게 비교할까? (Objects.equals(), equals(), == 비교 연산자) (0) | 2024.02.17 |
타입추론 var에 대해서 (0) | 2024.02.02 |
추상 클래스와 인터페이스 (0) | 2023.08.17 |