[ JAVA ] 14. Java의 구동 원리 및 JVM(Java Virtual Machine)에 대해 알아보자.
안녕하세요.
오늘은 자바라는 언어를 사용하면서 누구나 한번쯤은 생각해볼만한
자바는 어떻게 구동되어지는가 에 대해서 알아보도록 하겠습니다.
자바의 구동 원리
- 소스 코드 작성 ( .java 확장자 파일)
- 컴파일러인 javac.exe 가 소스 코드를 바이트 코드(Byte Code)로 변환 ( .class 확장자 파일)
- 런처인 java.exe 로 JVM(자바 가상 머신)을 구동
- JVM이 바이트 코드를 해석하여 자바 프로그램을 실행
위 순서에서 나온 바이트 코드란 JVM이 이해할 수 있는 언어로 변환된 코드를 말합니다.
JVM이 설치되어 있다면 바이트 코드를 이용해 어떤 운영체제에서라도 실행할 수 있게 됩니다.
추가로 JVM이 바이트 코드를 해석하는 과정에서
JVM은 Classath를 통해 클래스를 읽어드리고 이를 PERM 영역으로 올리게 됩니다.
* PERM 영역은 JDK8 version부터 Metaspace 영역으로 대체되었음.
JVM(자바 가상 머신)은 무엇인가?
일반적인 프로그램은 운영체제가 프로그램을 실행시키게 됩니다.
반면에, 자바는 운영체제가 JVM을 실행시키고, JVM이 바이트 코드를 실행시키게 됩니다.
즉, 자바의 바이트 코드들은 운영체제에서 직접 동작하는 것이 아닌 JVM을 통해 동작합니다.
이는 쉽게 말해 플랫폼의 독립성과 이식성을 높인다고 볼 수 있습니다.
다만, 플랫폼의 독립성에 따라 각 운영체제에 맞는 가상 머신을 설치해야 하기 때문에 운영체제에 종속적이긴 합니다.
또, 자바는 일반 프로그램보다 한 단계를 더 거치기 때문에 상대적으로 실행 속도가 느리다는 단점이 있습니다.
JVM을 왜 알아야 하는가?
조금 오래된 자료이긴 하지만, 위 사진을 보면 알 수 있습니다.
JVM과 메모리 부족이 정보시스템의 성능저하 요인의 많은 비중을 차지하고 있습니다.
시스템의 성능을 높이기 위해 JVM의 구성과 메모리를 아는 것은 자바를 사용하는 개발자로서 필수 불가결입니다.
특히, 메모리는 사용할 수 있는 공간이 한정되어 있기 때문에 어떻게 관리하냐에 따라 프로그램의 성능을 좌지우지합니다.
때문에, 메모리를 효울적으로 사용하기 위해서는 메모리의 구성과 그 특징에 대해서 이해할 필요가 있습니다.
JVM의 구조
- Class Loader : 런타임 시에 클래스 파일들을 JVM 내부로 로딩 및 클래스 파일을 분석한 뒤 각각의 Runtime Data Area에 배치한다. 자바는 동적 클래스를 읽어오므로 런타임 시에 모든 코드가 JVM과 연결된다.
- Runtime Data Area : Class Lodaer에서 분석된 클래스 파일의 데이터를 저장하고, 실행 도중 필요한 데이터를 저장한다. 메모리를 효율적으로 관리하기 위해서는 크게 5개 영역으로 구분하며, 간단히 말해 메모리 영역이라 부른다.
- Execution Engine : Runtime Data Area에 배치된 바이트 코드를 해석하며 실행한다. 이 때 인터프리터 방식과 JIT 컴파일 방식을 혼합 해석한다.
- 인터프리터 방식 : 바이트 코드를 한 줄씩 읽고 해석
- JIT(Just-In-Time) 컴파일 방식 : 바이트 코드를 런타임 시점에 바로 기계어로 변환
- 최초의 JVM은 인터프리터 방식만 사용하여 실행 속도가 느렸지만, JIT 컴파일 방식을 추가하며 이를 보완
- Garbage Collector : 시기에 따라 Gabage Collector가 메모리 관리 기능을 자동으로 수행하여 사용되지 않는 객체를 해제시켜 메모리를 반환한다.
자바의 메모리 영역
메모리 영역 | 용도 | 보존 기간 |
Method | 가장 먼저 데이이터가 저장되는 공간 Class Loader에 의해 Loading된 클래스가 저장됨 클래스 변수나 전역 변수를 무분별하게 많이 사용하면 메모리가 부족할 수 도 있음 |
프로그램의 시작부터 종료까지 메모리에 남음 명시적인 Null 선언 시 GC 청소대상 |
heap | 런타임 시 참조형 데이터 타입이 저장되는 공간 new 연산자를 통해 생성된 객체가 저장되는 공간 |
객체가 더 이상 쓰이지 않거나, 명시적인 Null 선언 시 GC 청소대상 |
Stack | 컴파일 시 결정되는 기본형 데이터 타입이 저장되는 공간 지역 변수, 매개 변수, 리턴값, 참조 변수 등을 저장 메서드 호출 시 메모리에 FILO로 하나씩 생성 메서드 종료 시 메모리에 LIFO로 하나씩 제거 메서드 호출 시 각각의 Stack Entry 생성 |
{ } 또는 메서드가 끝날 때까지 (Stack Entry 별로 삭제) |
PC Register | JVM이 수행 할 명령어의 주소를 저장하는 공간 | 스레드가 시작될 때마다 생성 |
Native Method Stack | 바이트 코드가 아닌 기계어로 작성된 코드를 실행하는 공간 다른 언어로 작성된 코드를 수행하기 위함 Java Native Interface를 통해 바이트 코드로 변환 |
Java Native Interface 호출 및 종료 시 생성 |
이상으로 자바의 구동 원리와 JVM에 대해 자세히 알아보았습니다.
자바를 활용하여 개발을 하게 된다면 필수로 거쳐야하는 이론이라 생각합니다.
자바는 다른 언어들과는 다르게 JVM을 활용한다는 점과 바이트 코드를 통해 프로그램이 실행된다는 점은 꼭 기억해야 합니다.