개발 기록
> JVM(Java Virtual Machine): 아키텍처 및 성능 분석 본문

■
1. JVM (Java Virtual Machine) 개념
☆기술적 정의 : 코드를 실행하고 해당 코드에 대해 런타임 환경을 제공하는 소프트웨어 프로그램 사양
☆ 일반적 정의 : 자바 바이트 코드를 실행할 수 있는 주체
(1) 특징
㉮ 스택 기반의 가상 머신
: 대다수의 명령어가 스택 선두에서 피연산자를 택하고 결과는 다시 스택에 넣는다.
: JVM은 가상 운영체제를 생성하지 않으므로, JVM을 관리되는 런타임 환경(Managed Runtime Environment) 또는 프로세스 가상 머신이라고 정의하는 것이 더 정확할 수도 있다.
㉯ 명령어에서 스택에서 가져올 피연산자의 타입을 명령어에 지정
㉰ 데이터 흐름 분석에 기반한 자바 바이트코드 검증기(verifier)를 통해 스택 넘침, 명령어 피연산자의 타입 규칙 위반, 필드 접근 규칙 위반, 지역 변수의 초기화 전 사용 등 많은 문제를 실행 전에 검증하여 안전을 보장하고 별도의 부담을 줄여줌
㉱ 가비지 컬렉션 사용 : 메모리 관리를 자동으로 해준다
㉲ JRE(Java Runtime Environment)의 일부
㉳ 운영체제와 플랫폼 종류에 의존적이지 않고 독립적으로 JAVA프로그램 실행
■
2. JVM 아키텍처 이해

■
3. JVM 세 가지 주요 하위 시스템

■
3-1. JVM 세 가지 주요 하위 시스템 - 1. 클래스 로더 (Class Loader)
ClassLoader는 클래스의 동적 로딩, 연결 및 초기화를 담당한다.
Java 애플리케이션을 실행하기 위한 런타임 환경을 제공하고,Java Compiler(자바 컴파일러)
에 의해 Java source(.java) 파일은 Byte code로 변환, 변환된 Byte code(.class) 파일을 JVM 내로 class를 로드하고 Link작업을 통해 배치 등 일련의 작업을 한다. 또 런타임시 class를 load한다.

(1) 세가지 주요 단계 (로딩, 연결, 초기)
▶1. 로딩
이 단계에서 클래스 로더는 클래스 파일의 바이너리 데이터를 읽고 이를 런타임 데이터 영역으로 가져온다. 현재 실행 중인 클래스에서 참조하는 클래스에 대해 이 작업을 수행하여 필요에 따라 클래스가 로드되도록 한다. 바이트 코드(.class 파일)를 메모리로 로드하는 역할을 담당하는 부분이다.
<<클래스 로더 유형>>
- 부트스트랩 클래스 로더: 핵심 Java 클래스(예: java.lang.Object)를 로드.
- 확장 클래스 로더: JRE 의 확장 디렉터리에서 클래스를 로드.
- 시스템/애플리케이션 로더 : 애플리케이션의 클래스 경로에서 클래스를 로드.
▶2. 연결
로드 후 JVM은 다음과 같은 연결 프로세스를 수행한다.
- 검증: .class 파일(바이트코드) 의 정확성을 보장한다.
- 준비: JVM은 클래스 변수에 메모리를 할당하고 이를 기본값으로 초기화 한다.
- 해결: 런타임 상수 풀의 기호 참조에서 직접 참조로 변환한다.
▶3. 초기화
클래스의 정적 필드에 원래 초기 값을 할당하고 정적 블록을 실행하는 클래스 로딩의 마지막 단계이다.
■
3-1. JVM 세 가지 주요 하위 시스템 - 2. 런타임 데이터 영역 (RunTimeData Area)

런타임 데이터 영역은 Java 어플리케이션이 실행하면서 할당받은 메모리영역이다 Java 애플리케이션 실행에서 중심 역할을 한다. 메모리의 효율적인 관리가 Java 애플리케이션 성능의 핵심이다. 런타임 데이터 영역은 여러 주요 영역으로 나누어진다.

(1) 메서드 영역
: 모든 스레드 간의 공유 리소스이며 다음을 위한 저장 공간 역할을 한다. 다음을 위한 저장 공간 역할을 합니다.
☞ 클래스 구조 : 런타임 상수 풀, 필드 및 메소드 데이터, 메소드 코드, 생성자 및 특수 메소드와 같은 클래스 구조
☞ 런타임 상수 풀 : 숫자 리터럴에서 메서드 및 필드 참조에 이르는 여러 종류의 상수를 포함하는 클래스 파일의 상수 풀에 대한 클래스별 런타임 표현
☞ 정적 변수: 클래스와 관련된 모든 정적 데이터.
★ 메소드 영역의 메모리를 사용할 수 없는 경우 Java Virtual Machine은 OutOfMemoryError 발생
(2) 힙 영역
: 공유 리소스이기도 하며 모든 클래스 인스턴스 및 배열에 대한 메모리가 할당되는 런타임 데이터 영역이다. 가상머신 시작 시 생성된다. 힙은 가비지 수집의 대상이므로 메모리 관리가 JVM 성능에 중요하다.
★ 힙의 효과적인 메모리 관리는 매우 중요하므로, 힙 메모리 사용량을 모니터링하고 애플리케이션 요구 사항에 따라 힙 크기 설정을 조정해야 한다. 객체의 힙 저장소는 가비지 컬렉터에 의해 회수되며 객체는 명시적으로 할당 해제되지 않는다.
(3) 스택 영역
각 스레드에는 스레드와 동시에 생성된 자체 스택있다. JVM 스택은 다음을 포함하는 데이터 구조인 프레임을 저장한다.
☞ 지역 변수 배열: 매개 변수, 지역 변수 및 중간 계산을 포함하여 메서드에서 사용되는 변수 집합
☞ 피연산자 스택: 중간 연산 결과를 저장하기 위한 작업 공간으로 사용되는 LIFO 스택
☞ 프레임 데이터: 메서드 반환 값과 메서드 코드 및 런타임 상수 풀에 대한 참조를 포함
★ JVM 스택은 메소드 실행에 매우 중요합니다. 메소드가 호출되고 완료됨에 따라 동적으로 확장되고 축소된다.
★ 스레드의 계산에 허용된 것보다 더 큰 스택이 필요한 경우 => StackOverflowError 발생
★ 확장 시도 시 사용할 수 있는 메모리 부족 또는 초기 스택을 생성 시 사용할 수 있는 메모리가 부족한 경우 => OutOfMemoryError 발생
(4) 프로그램 카운터(PC) 레지스터
: JVM에서 각 스레드에는 자체 PC(프로그램 카운터) 레지스터가 있다. PC 레지스터에는 현재 실행 중인 JVM 명령어의 주소가 포함되며, JVM 명령 시퀀스를 추적하고 스레드를 순서대로 실행하는 데 필수적이다.
(5) 네이티브 메서드 스택
: 애플리케이션에 사용되는 모든 네이티브 메서드가 포함되어 있다.
( C나 C++와 같은 Java 이외의 언어로 작성된 메소드 )
■
3-1. JVM 세 가지 주요 하위 시스템 - 3. 실행 엔진 (Execution Engine)
클래스 로더가 클래스를 로딩하는 작업을 마치면, 각 클래스에 있는 코드를 실행하는 역할이다.
(1) 엑세스 관리
코드 실행에는 시스템 리소스에 대한 액세스 관리가 관련되어 있다.
메모리를 넘어서, 실행 엔진은 파일 시스템 액세스, 네트워크 입출력을 위한 리소스를 관리한다. JVM 실행 엔진은 로그램 실행과 운영체제 가운데 위치해서 이런 리소스들을 공급한다.
(2) 컴파일러
프로그램을 실행하기 전에 바이트코드를 기계어 명령어로 변환해야 하는데, JVM은 다음을 사용할 수 있다.
1. 인터프리터(Interpreter) : 바이트코드 명령어를 한 줄씩 읽고 실행합니다. 한 줄씩 실행되기 때문에 인터프리터는 비교적 느리고 시스템 성능에 영향을 준다.
2. JIT(Just-In-Time) 컴파일러: 성능 향상을 위해 JVM에서는 JIT 컴파일러가 사용된다. CPU가 직접 실행할 수 있도록 전체 바이트코드를 기본 네이티브 코드로 컴파일한다.
(3) 가비지 컬렉터 (Garbage Collector)
백그라운드에서 실행되어 더 이상 사용되지 않는 개체를 제거하여 메모리 리소스를 확보합니다.
■
4. 메모리 관리
1. 힙 메모리 관리
- 메모리 사용량 모니터링: 힙 사용량을 정기적으로 모니터링 => 메모리 누수 식별 및 힙 크기 최적화에 도움
- 힙 덤프 분석: 메모리 누수와 과도한 메모리를 소비하는 개체 발견
2. 메모리 할당 전략
- 객체 풀링: 객체 재사용으로 힙 변동 감소
- 효율적인 데이터 구조: 메모리 사용량 및 액세스 속도 최적화.
3. 코드 최적화 기술
- 객체가 더 이상 필요하지 않을 때 더 이상 참조되지 않도록 한다. => 메모리 누수 방지
- 데이터 구조의 효율적인 사용: 작업에 적합한 데이터 구조를 선택
- 동기화 오버헤드 최소화
4. 모니터링 및 프로파일링
1. JVM 모니터링
- 메모리 사용량, CPU 활용도, 런타임 동작 모니터링
ex. 힙 메모리 사용량을 모니터링하면 메모리 누수를 조기에 감지하는 데 도움
ex. CPU 사용량을 관찰하면 비효율적인 코드 또는 동시성 문제를 알 수 있다.
2. Java 애플리케이션 프로파일링으로 JVM 성능 튜닝
- 병목 현상과 비효율성을 식별하기 위해 애플리케이션의 런타임 동작을 분석.
- 메서드 실행 시간, 메모리 할당, 스레드 활동 등 지표 파악 =>
ex. 특정 메서드가 비정상적으로 많은 양의 CPU 시간을 소비하고 있음을 밝혀 코드 최적화가 필요성을 알수있다.
3. JVM 모니터링 및 프로파일링 도구
1. VisualVM
2. JConsole
3. Java Mission Control
참고
https://www.linkedin.com/pulse/jvm-architecture-how-internally-work-ali-as-ad
https://www.itworld.co.kr/news/110837#csidx7bd952e6c151dadba1ce5ce840836e9

'JAVA' 카테고리의 다른 글
| > [Java] 직렬화 (Serializable) 에 대해서 3. Java 객체 직렬화/역직렬화 방법(Json, YAML, binary ) - GSON, YAML Bean, Protocol Buffers 등 (0) | 2020.12.14 |
|---|---|
| > [Java] 직렬화 (Serializable) 에 대해서 2. 의문점과 답변 정리 (0) | 2020.10.02 |
| > [Java] 직렬화 (Serializable) 에 대해서 1. 개념과 구현 (0) | 2020.09.22 |
| >[Java] static, final, 상수 개념과 사용 (0) | 2020.07.19 |
| >[Java] Java 객체지향 프로그래밍(OOP, Object-Oriented Programming)에 대하여 (0) | 2020.07.13 |