티스토리 뷰
들어가기전 아주 간단 용어 설명
- 컴파일 : 프로그래밍 언어로 작성한 소스코드를 중간언어인 바이트(바이너리)코드로 변환하는 작업
- 바이트(바이너리) 코드 : 프로그램 실행을 위한 0과 1로 이루어진 표현법
- JVM : Java Virtual Machine의 약자로 자바 가상 머신으로 물리적으로 존재하지 않은 가상 검퓨터
- JVM 실행 : JVM 프로세스가 운영체제에서 생성되고, Java 어플리케이션을 실행할 준비 완료
왜 JVM이 등장 했을까?
문제) 각 운영체제에 맞춰 컴파일하는 불편함
- Window로 C언어를 컴파일 한 것을 Mac 또는 Linux는 해당 컴파일 소스파일을 해석을 못하는 문제가 발생하였습니다.
- 즉, 배포된 환경의 운영체제와 아키텍처를 맞춰 컴파일했어야 했습니다.
해결) 혜성같이 등장
- 각 운영체제에 다운 받은 JVM이 컴파일하여 생긴 바이트 코드를 해당 운영체제에 맞게 해석하여 실행해줍니다.
- 즉, JVM은 각 운영체제에 독립적으로 애플리케이션을 실행하게 할 수 있다는 것입니다.
JVM 아키텍처 구조 및 각 간단 설명
Class Loader (클래스 로더)
- JVM이 실행될 때, 가장 먼저 클래스 로더가 동작하여 컴파일된 .class 파일(바이트 코드)을 메모리(Runtime Data Area)로 로드하는 역할
Runtime Data Area (런타임 데이터 영역)
- JVM이 실행될 때 사용하는 메모리 공간
- Method Area (메서드 영역) → 클래스 메타데이터인 클래스명, 메서드, 필드, 변수 등 저장
- Heap (힙 영역) → 프로그램을 실행하면서 생성한 모든 객체 인스턴스를 Heap에 저장
- Java Stack (스택 영역) → 메서드 호출 시 각 스레드마다 독립적인 스택 프레임을 저장
- PC Register (PC 레지스터) → 현재 실행 중인 메서드 명령어 주소 저장
- Native Method Stack (네이티브 메서드 스택) → JNI(Java Native Interface)를 통한 네이티브 코드 실행
Execution Engine (실행 엔진)
- 바이트코드를 실행하는데 처음엔 인터프리팅 방식으로 실행하다가, 특정 코드가 반복 실행되면 JIT 컴파일러가 네이티브 코드로 변환하여 속도를 향상시키는 역할
- 인터프리터 → 바이트 코드를 한 줄 씩 해석하면서 실행
- JIT 컴파일러 → 반복적으로 실행되는 코드를 기계어로 변환하여 최적화
- Garbage Collector (GC) → Heap 영역에서 불필요한 객체를 정리하는 역할을 수행
Java Native Interface (JNI, 네이티브 인터페이스)
- Java에서 C/C++같은 네이티브 코드를 실행할 수 있도록 지원하는 역할
- 즉, 런타임 데이터 영역의 네이티브 메서드 스택에서 네이티브 코드를 실행할 수 있게 지원
Native Method Libraries (네이티브 메서드 라이브러리)
- JNI를 통해 호출되는 네이티브 라이브러리 (C, C++ 코드)
JVM이 실행되는 과정
대략적인 흐름만 설명하였고, 자세한건 이후 아래 글에 설명하겠습니다.
- 개발자가 .java 파일에 Java 소스 코드 작성합니다.
- 컴파일 하어 .class 파일인 바이트 코드가 생성됩니다.
- JVM이 실행될 때 가장먼저 클래스 로더가 동작하여 .class파일을 메모리에 로드합니다.
- 컴파일된 바이트코드를 실행하여 인터프리터 방식 및 JIT 컴파일러로 실행합니다.
- 프로그램 실행 중에 힙, 스택, 메서드 영역 등 활용하여 메모리 관리를 합니다.
- 실행 중에 더 이상 사용되지 않는 객체를 가비지 컬렉션이 정리합니다.
- 프로그램 종료했을 때 JVM은 모든 메모리 해제하여 종료합니다.
Class Loader (클래스 로더)
위에서 간단 설명으로 컴파일된 바이트코드를 메모리에 로드하는 역할을 한다고 하였습니다.
클래스 로딩과정과 무엇을 로딩할까? 정도만 알아보도록 하겠습니다.
1. 클래스 로딩 (Loading)
- 바이트 코드를 가져와서 JVM에 로드합니다.
- ClassLoader 라는 클래스 로딩 담당 객체에 의해 이루어집니다.
즉, 클래스 파일이 저장된 경로에서 클래스를 찾아 JVM에 로드합니다.
2. 클래스 링크 (Linking)
- 바이트 코드를 사용하기 위해 검증하는 과정입니다.
- [검증] 클래스 파일이 유효한지 확인하고 JVM이 처리할 수 있는 형식인지 검사합니다.
- [준비] 클래스 static 변수들이 기본 값으로 초기화됩니다.
즉, 변수들이 메모리에 배치되고 기본 값으로 할당됩니다. - [분석] 클래스에서 참조하는 다른 클래스나 메소드, 필드를 실제 메모리 주소로 변환하는 과정입니다.
3. 클래스 초기화 (Initialization)
- 클래스 변수들을 할당한 값으로 재할당합니다.
- static 블록이 있다면 해당 블록이 실행됩니다.
- 해당 초기화는 클래스가 처음 사용될 때 또는 Class.forName()을 통해 명시적으로 로드할 때 발생합니다.
어떤 클래스를 로딩을 어떤 순서로?
- Bootstrap : java.lang 패키지 등 기본적인 핵심 Java 클래스를 로드 (기본클래스)
- Extension : lib/ext 디렉토리에 있는 확장 클래스를 로드 (라이브러리 클래스)
- Application : 사용자가 작성한 클래스 로드 (커스텀 클래스)
Execution Engine (실행 엔진)
위에서 간단 설명으로 컴파일된 바이트 코드를 실행하는 역할을 한다고 하였습니다.
실행할 때 2가지의 방법으로 실행됩니다.
Interpreter (인터프리터)
- 바이트 코드를 한 줄 씩 해석하여 실행합니다.
- 바로 실행이 가능하기 때문에 빠른 시작이 장점이며, 한 줄 씩 해석해야하기 때문에 실행속도가 느립니다.
Just-In-Time (JIT 컴파일러)
- 반복적으로 실행되는 코드를 기계어(네이티브 코드)로 변환하여 최적화 합니다.
결론으론, JVM은 처음에는 인터프리터 방식으로 실행하다가, 특정 코드가 반복 실행되면 JIT 컴파일러가 네이티브 코드로 변환하여 실행속도를 향상시킵니다.
Garbage Collector (GC, 가비지 컬렉터)
- Heap영역에서만 동작하며 사용하지 않는 객체를 자동으로 정리해줍니다.
- Minor GC(Young Generation), Major GC(Old Generation) 으로 동작됩니다.
Runtime Data Area (런타임 영역 데이터)
위에서 간단하게 설명했지만 JVM이 실행할 때 사용하는 메모리 공간이라고 하였습니다.
Method Area (메소드 영역)
- 모든 스레드가 공유합니다.
- 클래스 로더가 바이트 코드를 메모리에 로드한다고 하였는데 이 곳에 클래스의 메타데이터들을 저장합니다.
Heap (힙 영역)
- 모든 스레드가 공유합니다.
- 프로그램을 실행하면서 생성한 모든 객체 인스턴스를 저장합니다.
PC Register (PC 레지스터)
- 각 스레드마다 독립적으로 존재합니다.
- 각 스레드의 실행 중인 바이트 코드(명령어)의 주소를 저장합니다.
- 메서드 안에서 몇 번째 줄을 실행해야하는지 저장합니다.
Java Stack (스택 영역)
- 자바 스택은 각 스레드 별로 1개만 존재하고, 스택 프레임은 메서드가 호출될 때마다 생성됩니다.
- 각 스레드별 스택 프레임을 저장합니다.
- 스택 프레임
- 메서드가 호출될 때마다 새로 생겨 스택에 추가(push) 됩니다.
- 메서드 실행이 끝나면 스택에서 제거(pop) 됩니다.
- 스택 프레임은 지역변수(Local variables array), 메서드 내 연산 작업 공간(Operand stack), Frame Data를 갖습니다.
- Frame Data는 Constant Pool, 이전 스택 프레임에 대한 정보, 현재 메서드가 속한 클래스/객체에 대한 참조 등의 정보를 갖는다.
Native Method Stack (네이티브 메서드 스택)
- Java Bytecode가 아닌 다른 언어(C, C++)로 작성된 코드가 실행되는 메서드의 스택을 관리하는 영역입니다.
- JNI (Java Native Interface)를 통해 호출된 네이티브 코드의 스택 프레임을 저장합니다.
- 가끔 성능 향상을 목적으로 다른 컴파일 언어로 작성한게 있다고 합니다.
실무 꿀팁
OutOfMemoryError가 발생하면 어떻게 할것인가?
- Java heap space : Heap 메모리 부족 (대부분)
⇒ 원인 : 객체 과다 생성, 지속적인 메모리 누수, 일시적인 과도한 요청
⇒ 해결 방법 : 객체 수명 관리하기, 불필요한 객체 생성 줄이기 - Metaspace : 클래스 메타데이터 공간 부족 (클래스 동적 로드가 많을 때)
⇒ 원인 : 동적 클래스 로딩 과다 (라이브러리가 class를 양산하고 있을 수도 있다)
⇒ 해결 방법 : 라이브러리가 과도하게 프록시 클래스 만드는 구조인지 점검 - GC overhead limit exceeded : GC가 너무 자주 돌아서 성능이 심각하게 저하된 경우
⇒ 원인 : GC 반복 과부하, GC가 메모리를 정리하는데 너무 많은 시간과 반복적 실패를 했을 경우
⇒ 원인 : JVM GC를 수행하는 시간의 98%를 소비했지만 Heap 메모리의 2% 미만으로 복구되는 경우
⇒ 해결 방법 : GC 로그 통해 어떤 영역에서 문제인지 확인
⇒ 해결 방법 : DTO 필드 최소화, Jackson/Gson 등 직렬화 라이브러리 튜닝, ThreadLocal 객체 누수 여부 확인 - Direct buffer memory : NIO direct buffer 메모리 부족
- unable to create new native thread : OS 레벨에서 스레드 생성 불가
⇒ 원인 : OS 스레드 리소스 부족
⇒ 해결 방안 : 스레드 리소스를 늘린다. 리눅스OS면 ulimit -u 로 제한을 푼다
스레드 풀을 크게하면 왜 OutOfMemory가 발생할 수 있을까?
- 스택 오버헤드 (OutOfMemoryError: unable to create new native thread)
⇒ JVM이 운영체제로부터 새로운 스레드를 생성하려고 할 때 OS가 더이상 메모리를 생성, 할당할 수 없을 때 발생한다. - 힙 메모리 부족 (OutOfMemoryError: Java heap space)
⇒ 작업 큐에 쌓이는 객체가 많아져서 힙메로리 초과가 발생한다. - GC 오버헤드 (OutOfMemoryError: GC overhead limit exceeded)
⇒ 너무 많은 스레드가 발생하면 GC가 계속 발생하여 CPU사용률이 높아져서 애플리케이션이 멈추는 문제가 발생한다.
참조 문서
https://www.artima.com/insidejvm/ed2/jvm2.html
Java Virtual Machine's Internal Architecture
Chapter 5 of Inside the Java Virtual Machine The Java Virtual Machine by Bill Venners << Page 2 of 13 >> Advertisement The Architecture of the Java Virtual Machine In the Java virtual machine specification, the behavior of a virtual machine instance
www.artima.com

감사합니다.
'프로그래밍 언어 > 💫JAVA' 카테고리의 다른 글
[JAVA] 객체지향 프로그래밍을 배우는 블랙잭 게임 (4/4) : 개선 사항 및 후기 (1) | 2024.06.24 |
---|---|
[JAVA] 객체지향 프로그래밍을 배우는 블랙잭 게임 (3/4) : 비즈니스 로직 개발 및 실행 (2) | 2024.06.18 |
[JAVA] 객체지향 프로그래밍을 배우는 블랙잭 게임 (2/4) : 도메인 개발 (0) | 2024.06.12 |
[JAVA] 객체지향 프로그래밍을 배우는 블랙잭 게임 (1/4) : 설계 단계 (0) | 2024.06.06 |
[JAVA] 멀티쓰레드와 쓰레드 풀 : 동시 프로그래밍의 핵심 (0) | 2024.02.14 |
- Total
- Today
- Yesterday
- Cors
- 네트워크
- AJAX
- 자바스크립트
- DBeaver
- 템플릿
- Fetch
- 디자인패턴
- Mac
- aws
- 프론트
- 개발
- git
- JavaScript
- spring
- java
- 데이터 베이스
- Front
- 개발자
- 오라클
- 비동기
- 깃허브 액션
- 개발블로그
- 코딩테스트
- 프로세스
- 개발환경
- Spring Security
- jvm
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |