To Dare Is To Do!
JVM과 자바의 컴파일 과정 본문
JVM이란?
JVM이란 Java Virtual Machine으로 자바 프로그램을 실행하기 위한 가상 머신이다.
컴파일된 바이트 코드를 플랫폼(운영체제, CPU 등)이 인식할 수 있도록 기계어로 변환해 준다.
이를 통해 자바는 어떠한 운영체제에서도 JVM만 있으면 실행될 수 있다.
🗒정리
JVM은 운영체제를 대신하여 컴파일된 바이트 코드를 실행하는 가상의 운영체제로서 자바가 운영체제로부터 독립적으로 프로그램을 실행할 수 있게 해준다.
(JVM은 운영체제에 의존하기 때문에 윈도우용 JVM, 리눅스용 JVM 등이 따로 존재)
JVM 특징
- 스택 기반의 가상 머신
- 대표적인 컴퓨터 아키텍처인 인텔 x86 아키텍처나 ARM 아키텍처와 같은 하드웨어가 CPU 내 여러 레지스터에 데이터를 저장하고 연산하는 반면 JVM은 스택이라는 메모리 구조에 데이터를 저장하고 연산할 때 스택의 상단에 있는 데이터를 사용하는 단순한 방식으로 동작함으로써 하드웨어 플랫폼의 제약 없이 사용 가능하다.
- 심볼릭 레퍼런스
- 기본 자료형(primitive data type)을 제외한 모든 타입(클래스와 인터페이스)을 명시적인 메모리 주소 기반의 레퍼런스가 아니라 심볼릭 레퍼런스를 통해 참조한다.
*심볼릭 레퍼런스
심볼릭 레퍼런스는 참조하는 대상의 이름을 지칭하고, 자바 바이트 코드(.class)가 JVM에 올라가게 되면 심볼릭 레퍼런스는 이름에 맞는 객체의 물리적인 주소를 찾아서 연결하는 작업을 수행한다.
이로 인해 개발자는
추상화 (실제 메모리 주소나 복잡한 경로를 신경쓰지 않고 추상적인 이름으로 작업 가능),
유연성 (데이터나 객체의 실제 위치가 변경되어도 심볼릭 레퍼런스를 통해 접근 가능),
가독성 등의 효과를 얻을 수 있음
- 가비지 컬렉션(garbage collection)
- 클래스 인스턴스는 사용자 코드에 의해 명시적으로 생성되고 가비지 컬렉션에 의해 자동으로 파괴된다.
- 기본 자료형을 명확하게 정의하여 플랫폼 독립성 보장
- JVM은 기본 자료형을 명확하게 정의하여 호환성을 유지하고 플랫폼 독립성을 보장한다.
- C/C++ 등의 전통적인 언어는 플랫폼에 따라 int 형의 크기가 변하지만 자바의 int 타입은 32비트로 명확하다.
자바의 컴파일 과정
1. 개발자가 자바 소스코드(.java)를 작성
2. 작성된 자바 소스코드는 자바 컴파일러의 컴파일 과정을 통해 자바 바이트 코드(.class)*로 변환됨
3. 컴파일된 바이트 코드는 JVM의 클래스 로더(Class Loader)에게 전달
4. 클래스 로더는 동적 로딩을 통해 필요한 클래스들을 로딩 및 링크하여 데이터 영역(Runtime Data Area),
즉 JVM의 메모리에 적재됨
5. 실행엔진(Execution)은 JVM 메모리에 올라온 바이트 코드들을 명령어 단위로 하나씩 가져와 실행
*바이트 코드
- 각 명령어가 1바이트 크기의 Opcode와 추가 피연산자로 구성되어 있으며 아직 컴퓨터가 읽을 수 없는 코드
- JVM(자바 가상 머신)이 이해할 수 있는 코드
- 확장자는 .class
자바는 C, C++ 언어처럼 운영체제 별 컴파일러가 존재하는 것이 아닌 자바 컴파일러 하나만이 존재하며
이는 기계어가 아닌 중간 단계의 바이트 코드를 생성하여 JVM이 실행토록 한다.
JVM의 구조
클래스 로더
JVM 내로 클래스 파일(.class)을 동적으로 로드하고 링크를 통해 배치하는 작업을 수행
동적 로딩 : 컴파일 타임이 아니라 런타임에 클래스를 로드하고 인스턴스 생성
클래스 로더는 로딩, 링크, 초기화 단계로 나뉨
- 로딩
- 바이트 코드(.class)는 JVM에 의해 다음과 같은 정보를 메소드 영역에 저장한다.
- 로드된 클래스를 비롯한 그의 부모 클래스의 정보
- 클래스 파일과 Class, Interface, Enum의 관련 여부
- 변수나 메소드 등의 정보
- 바이트 코드(.class)는 JVM에 의해 다음과 같은 정보를 메소드 영역에 저장한다.
- 링크
- 검증 : 읽어 들인 클래스가 자바 언어 명세 및 JVM 명세에 명시된 대로 잘 구성되어 있는지 검사
- 준비 : 클래스가 필요로 하는 메모리를 할당하고, 클래스에서 정의된 필드, 메서드, 인터페이스를 나타내는 데이터 구조 준비
- 분석 : 심볼릭 메모리 레퍼런스*를 메서드 영역에 있는 실제 레퍼런스로 교체
- 초기화
- 클래스 변수들을 적절한 값으로 초기화 한다. 즉. static 필드들이 설정된 값으로 초기화
런타임 데이터 영역 (메모리)
JVM의 메모리 영역으로 자바 애플리케이션을 실행할 때 사용되는 데이터들을 적재하는 영역
JVM이 운영체제 위에서 실행될 때, 할당받는 메모리 영역
이 영역들은 스레드가 공유하는 공간인지 아닌지로 나눌 수 있다.
- 모든 스레드가 공유하는 공간
- 힙
- 메소드
- 런타임 상수 풀
- 스레드마다 하나씩 생성되는 공간
- PC 레지스터
- 스택
- 네이티브 메소드 스택
힙 (Heap Area)
- 프로그램 상 데이터를 저장하기 위해 런타임 시 동적으로 할당하여 사용하는 메모리 영역
- New 연산자를 통해 생성한 객체나 인스턴스와 배열을 저장
- JVM이 관리
메소드 (Method Area)
JVM(클래스 로더)에서 읽어들인 클래스와 인터페이스에 대한 런타임 상수 풀, 메서드와 필드, Static 변수, 메서드 바이트 코드 등을 보관
PC 레지스터
- 현재 실행 중인 JVM의 주소를 가지고 있음
- CPU 명령어를 실행
- 연산 결과 및 결과값을 메모리에 전달하기 전 CPU 내 기억장치
JVM 스택
- 선입후출 구조
- 스레드가 시작될 때 생성
- 스택 프레임이라는 구조체로 이루어져 있으며 새로운 매소드가 호출될 때마다 push, 메서드 실행이 끝나면 pop
- 각 스택 프레임은 **지역 변수 배열(Local Variable Array), 피연산자(Operand Stack), 프레임 데이터(Frame Data)**를 갖음
Frame 데이터
메서드가 속한 클래스의 런타임 상수 풀, 시전 스택 프레임에 대한 정보, 현재 메서드가 속한 클래스, 객체에 대한 참조를 의미
네이티브 메소드 스택
- 자바가 아닌 다른 언어로 작성된 네이티브 코드를 위한 메모리
- C / C++ 등의 코드를 수행하기 위한 스택
- 성능 향상을 목적으로 작성
- 네이티브 메서드의 매개변수, 지역변수 등을 바이트 코드로 저장
런타임 상수 풀
- 메서드 영역에 포함
- 각 클래스와 인터페이스의 상수뿐만 아니라, 메서드와 필드에 대한 모든 레퍼런스까지 담고 있는 테이블
- 메서드나 필드를 참조할 때 JVM은 런타임 상수 풀을 통해 해당 메서드나 필드의 실제 메모리상 주소를 찾아서 참조
실행 엔진
JVM 메모리에 올라온 바이트 코드들을 명령어 단위로 하나씩 가져와서 다음과 같은 방식을 통해 실행
- 인터프리터 :
- 바이트 코드 명령어를 하나씩 읽어서 해석하고 실행
- 하나하나의 실행은 빠르나, 전체적인 실행 속도가 느림
- JIT 컴파일러(Just-In-Time Compiler) :
- 인터프리터의 단점을 보완하기 위해 도입된 방식
- 바이트 코드 전체를 컴파일하여 바이너리 코드로 변경하고 이후에는 해당 메서드를 더이상 인터프리팅 하지 않고, 바이너리 코드로 직접 실행하는 방식
- 하나씩 인터프리팅하여 실행하는 것이 아니라 바이트 코드 전체가 컴파일된 바이너리 코드를 실행하는 것이기 때문에 전체적인 실행속도는 인터프리팅 방식보다 빠름
참고
https://gyoogle.dev/blog/computerlanguage/Java/%EC%BB%B4%ED%8C%8C%EC%9D%BC%20%EA%B3%BC%EC%A0%95.html
[Java] 컴파일 과정 | 👨🏻💻 Tech Interview
[Java] 컴파일 과정 들어가기전 자바는 OS에 독립적인 특징을 가지고 있다. 그게 가능한 이유는 JVM(Java Vitual Machine) 덕분이다. 그렇다면 JVM(Java Vitual Machine)의 어떠한 기능 때문에, OS에 독립적으로
gyoogle.dev
'Java' 카테고리의 다른 글
오버로딩과 오버라이딩 (0) | 2024.07.04 |
---|---|
자바 메모리 구조 (feat 자바 변수) (0) | 2024.06.12 |
클래스를 왜 쓰는지 다시 한번 생각해 보자! (0) | 2023.12.21 |
인터페이스가 가지는 객체 지향의 특징 (0) | 2023.10.21 |
[java]객체 지향 프로그래밍이란? (0) | 2023.10.20 |