공식 JVM 명세 The Java Virtual Machine Specification, Java SE 11 Edition 문서이고 번역은 파파고로 했다.
-> 표시 뒤 문장은 내가 단 주석이다.
명세 중 JVM에서 다루는 데이터 유형과 Run-time Data Areas에 대한 내용이다.
JVM이란?
JVM은 추상적인 컴퓨팅 머신이다. 실제 컴퓨팅 머신처럼, 그것은 명령어 세트를 가지고 있고 실행 시 다양한 메모리 영역을 조작한다.
JVM은 자바 프로그래밍 언어에 대해 전혀 알지 못하며, 특정 바이너리 형식, 클래스 파일 형식만 알고 있다. 클래스 파일에는 Java Virtual Machine 명령(또는 바이트 코드)과 기호 테이블 및 기타 보조 정보가 포함되어 있습니다.
형식 및 데이터 유형
1. class 파일 형식
JVM에 의해 실행될 컴파일된 코드는 일반적으로 클래스 파일 포맷으로 알려진 파일에 저장된 하드웨어 및 운영 체제 독립 바이너리 포맷을 사용하여 표현된다.
-> 컴파일된 자바 바이트 코드는 하드웨어, 운영 체제에 독립적인 바이너리 포맷으로 클래스 파일에 저장되어 있다.
2. 데이터 유형
JVM은 자바 프로그래밍 언어와 마찬가지로 두 가지 유형으로 동작한다: 원시 유형과 참조 유형(primitive types and reference types)
거의 모든 유형 검사(type checking)가 일반적으로 컴파일러에 의해 실행 시간 전에 수행되며 JVM 자체에 의해 수행될 필요는 없다.
원시 유형의 값(primitive types)은 런타임에 유형을 결정하거나 참조 유형의 값과 구별하기 위해 태그를 지정하거나 검사할 필요가 없습니다.
대신 JVM의 명령 집합은 특정 유형의 값에 대해 작동하기 위한 명령을 사용하여 피연산자 유형을 구분합니다.
예를 들어 iadd, ladd, fadd 및 dadd는 모두 두 개의 숫자 값을 추가하고 숫자 결과를 생성하는 JVM 명령이지만 각각 int, long, float 및 double의 피연산자 유형에 특화되어 있습니다.
JVM에는 개체에 대한 명시적 지원이 포함되어 있습니다.
개체는 동적으로 할당된 클래스 인스턴스 또는 배열입니다. 개체에 대한 참조는 JVM 유형 참조가 있는 것으로 간주됩니다.
유형 참조 값은 객체에 대한 포인터로 생각할 수 있습니다. 개체에 대한 참조가 두 개 이상 있을 수 있습니다.
개체는 항상 유형 참조 값을 통해 작동, 전달 및 테스트됩니다.
3. 기본 유형 및 값
JVM에서 지원하는 기본 데이터 유형은 숫자 유형, boolean 유형 및 returnAddress 유형입니다.
숫자 유형은 적분 유형(Integral)과 부동 소수점 유형(floating-point)으로 구성됩니다.
적분 유형: byte, short, int, long, char
부동 소수점 유형: float, double
returnAddress 유형의 값은 JVM 명령의 opcode에 대한 포인터입니다.
원시 유형 중 returnAddress 유형만 Java 프로그래밍 언어 유형과 직접 연관되지 않습니다.
4. 참조 유형 및 값
참조 유형에는 클래스 유형, 배열 유형 및 인터페이스 유형의 세 가지 유형이 있습니다.
참조 값은 특수한 null 참조일 수 있으며, 이는 여기서 null로 표시될 개체 없음에 대한 참조입니다. null 참조에는 처음에는 런타임 유형이 없지만 모든 유형에 캐스팅될 수 있습니다. 참조 유형의 기본값은 null입니다.
이 명세는 구체적인 값 인코딩 null을 요구하지 않습니다.
Run-Time Data Areas
JVM은 프로그램 실행 중에 사용되는 다양한 런타임 데이터 영역을 정의합니다.
이러한 데이터 영역 중 일부는 JVM 시작 시 생성되며 JVM이 종료될 때만 삭제됩니다.
다른 데이터 영역은 스레드 당(per-thread)입니다. 스레드별 데이터 영역은 스레드가 생성되고 스레드가 종료될 때 삭제됩니다.
-> Heap, Method area는 JVM과, 그 외 PC register, JVM stacks, Native Method Stacks는 스레드와 생명주기를 같이 한다.
1. PC Register
JVM은 한 번에 많은 실행 스레드를 지원할 수 있습니다.
각 JVM 스레드는 자체 pc(프로그램 카운터) 레지스터를 가집니다.
어느 시점에서든 각 JVM 스레드는 단일 메서드의 코드, 즉 해당 스레드에 대한 현재 메서드를 실행합니다.
이 메서드가 네이티브가 아닌 경우 pc 레지스터에 현재 실행 중인 JVM 명령의 주소가 포함됩니다.
스레드에서 현재 실행 중인 메서드가 네이티브인 경우 JVM의 pc 레지스터 값이 정의되지 않습니다.
-> 여기서 네이티브란 C, C++ 같은 자바 외 언어로 작성된 코드이다.
예를 들어, JNI(Java Native Interface)를 통해 호출하는 C/C++ 등의 코드를 수행한다.
자바에서 왜 다른 언어를 사용할까?
성능 향상 또는 재사용을 위해 다른 언어로 만든 '모듈'을 사용할 수도 있고, 다른 언어를 통해서만 하드웨어나 OS에 접근할 수도 있다고 한다.
2. JVM Stacks
각 JVM 스레드에는 스레드와 동시에 생성되는 private JVM 스택이 있습니다. JVM 스택은 프레임을 저장합니다.
JVM 스택은 C와 같은 기존 언어의 스택과 유사하다. 로컬 변수와 부분 결과를 보유하고 메서드 호출 및 반환에 역할을 합니다.
JVM 스택은 푸시 및 팝 프레임을 제외하고 직접 조작되지 않으므로 프레임이 힙 할당될 수 있습니다. JVM 스택의 메모리는 연속할 필요가 없습니다.
JVM 스택과 관련된 예외 조건은 다음과 같습니다.
• 스레드의 계산에 허용된 것보다 더 큰 JVM 스택이 필요한 경우 JVM이 StackOverflowError를 발생시킵니다.
• JVM 스택을 동적으로 확장할 수 있고 확장하려고 하지만 메모리가 부족하여 확장을 적용할 수 없거나 새 스레드에 대한 초기 Java Virtual Machine 스택을 생성할 수 있는 메모리가 부족하면 Java Virtual Machine에서 OutOfMemory 오류가 발생합니다.
3. Heap
JVM에는 모든 JVM 스레드 간에 공유되는 힙이 있습니다.
힙은 모든 클래스 인스턴스 및 배열에 대한 메모리가 할당되는 런타임 데이터 영역입니다.
개체의 힙 저장소는 가비지 수집기(Garbage Collector)로 알려진 자동 스토리지 관리 시스템에 의해 회수되며, 개체는 명시적으로 할당 해제되지 않습니다.
힙은 고정된 크기일 수도 있고, 계산의 요구에 따라 확장될 수도 있으며, 더 큰 힙이 불필요해지면 수축될 수도 있다. 힙에 대한 메모리는 연속적일 필요가 없습니다.
힙과 관련된 예외 조건은 다음과 같습니다.
• 계산에 자동 스토리지 관리 시스템(GC)에서 사용할 수 있는 것보다 더 많은 힙이 필요한 경우 JVM이 OutOfMemoryError를 발생시킵니다.
4. Method Area
JVM에는 모든 JVM 스레드 간에 공유되는 메서드 영역이 있습니다.
메소드 영역은 전통적인 언어의 컴파일된 코드의 저장 영역과 유사하거나 운영 체제 프로세스의 "텍스트" 세그먼트와 유사하다.
런타임 상수 풀, 필드 및 메서드 데이터, 메서드 및 생성자 코드와 같은 클래스별 구조체(클래스 및 인터페이스 초기화 및 인스턴스 초기화에서 사용되는 특수 메서드 포함)를 저장합니다.
5. 런타임 상수 풀
런타임 상수 풀(run-time constant pool)은 클래스 파일의 constant_pool 테이블의 클래스 단위 또는 인터페이스 단위 런타임 표현이다.
컴파일 시 알려진 숫자 리터럴부터 런타임 시 해결되어야 하는 메서드 및 필드 참조에 이르기까지 여러 종류의 상수가 포함되어 있습니다.
각 런타임 상수 풀은 JVM의 메서드 영역에서 할당됩니다. 클래스 또는 인터페이스에 대한 런타임 상수 풀은 JVM에 의해 클래스 또는 인터페이스가 생성될 때 구성됩니다.
다음 예외 조건은 클래스 또는 인터페이스의 런타임 상수 풀 구성과 관련이 있습니다.
• 클래스 또는 인터페이스를 생성할 때 런타임 상수 풀을 구성하는 데 JVM의 메서드 영역에서 사용할 수 있는 것보다 많은 메모리가 필요한 경우 JVM이 OutOfMemoryError를 발생시킵니다.
6. Native Method Stacks
JVM의 구현은 네이티브 메서드(자바 프로그래밍 언어가 아닌 언어로 작성된 메서드)를 지원하기 위해 C 스택이라고 불리는 기존의 스택을 사용할 수 있다.
네이티브 메서드 스택은 또한 C와 같은 언어로 된 JVM의 명령어 집합을 위한 인터프리터의 구현에 의해 사용될 수 있다.
네이티브 메서드 스택과 관련된 예외 조건은 다음과 같습니다.
• 스레드의 계산에 허용된 것보다 더 큰 기본 메서드 스택이 필요한 경우 JVM이 StackOverflowError를 발생시킵니다.
• 네이티브 메서드 스택을 동적으로 확장할 수 있고 네이티브 메서드 스택 확장을 시도했지만 메모리가 부족하거나 새 스레드에 대한 초기 네이티브 메서드 스택을 만드는 데 사용할 수 있는 메모리가 부족하면 JVM이 OutOfMemoryError를 발생시킵니다.
'Study > Java' 카테고리의 다른 글
자바의 함수형 프로그래밍 전략, 메서드 참조 (0) | 2023.05.04 |
---|---|
[Java] 제네릭 (0) | 2023.02.01 |
자바로 간단한 http 웹 서버 구현 (0) | 2022.06.11 |
간단한 자바 TCP 통신 구현 (0) | 2022.06.02 |
자바 빌더 패턴 Java Builder Pattern (0) | 2022.05.31 |