JVM에 대해서 아시나요?
JVM이란 Java로 개발한 프로그램을 실행하기 위한 가상머신입니다.
운영체제 위에서 동작하므로 플랫폼에 독립적으로 Java 프로그램을 실행시킬 수 있습니다.
자바 프로그램 실행과정
(그림 출처 : https://medium.com/@lazysoul/jvm-%EC%9D%B4%EB%9E%80-c142b01571f2)
- 프로그램이 실행되면 JVM은 OS로부터 해당 프로그램이 필요로하는 메모리를 할당받습니다. JVM은 할당 받은 메모리를 용도에 따라 여러 영역으로 나누어 관리합니다.
- 자바 컴파일러(javac)가 자바 코드(.java)를 읽어 자바 바이트코드(.class)로 변환시킵니다.
- 클래스 로더는 class파일들을 JVM으로 로딩합니다.
- 로딩된 class파일들은 실행 엔진(Execution engine)을 통해서 해석됩니다.
- 해석된 바이트코드는 Runtime Data Areas에 배치되어 실질적인 수행이 이루어집니다. 이러한 실행과정 속에서 JVM은 필요에 따라서 GC를 수행합니다.
[참고 : https://asfirstalways.tistory.com/158]
JVM 주요 시스템
Class Loader (클래스 로더)
- .class 파일을 동적으로 로드, 링크를 통해 배치
Runtime Data Area (JVM 메모리영역)
- 프로그램을 수행하기 위해 OS에서 할당받은 메모리 공간
Execution Engine (실행 엔진)
클래스를 실행시키는 역할
바이트코드(인간 언어)를 Native코드(기계 언어)로 변경
구성
Interpreter (인터프리터)
- 자바 바이트코드를 명령어 단위로 읽어서 실행
- 한 줄 씩 수행하므로 느리다는 단점이 있음.
JIT (Just - In - Time)
- 인터프리터 단점을 보완한 방식
- 인터프리터 방식으로 실행하다가 적절한 시점에 바이트코드 전체를 컴파일하여 네이티브 코드로 변경하고, 이후에는 더 이상 인터프리팅 하지 않고 네이티브 코드로 직접 실행하는 방식
- 네이티브 코드는 캐시에 보관하므로 한 번 컴파일된 코드는 빠르게 실행
- 컴파일 하는 과정은인터프리터 방식보다 훨 씬 오래걸리므로 한 번만 실행되는 코드라면 인터프리터 방식을 쓰는 것이 유리하다.
Gabage Collection
- GC를 수행하는 모듈 (쓰레드)이 있다.
Runtime Data Area
프로그램을 수행하기 위해 OS에서 할당받은 메모리 공간
각 Thread 마다 생성 : PC Registers, Native Method Stack, Stack
모든 Thread들이 공유하는 영역 : Heap, Method Area
PC Registers
- 현재 실행 중인 명령의 주소가 저장되는 공간
Native Method Stack
- Native 언어 (C언어)의 메서드가 실행될 경우 저장되는 공간
Stack
- 메서드 관련 작업을 수행하는 공간
- Stack 자료구조 LIFO 방식
Heap
- 인스턴스(객체)와 배열을 저장하는 공간
- GC의 대상이 되는 공간 (JVM의 주요 메모리이슈 발생구간)
Method Area
적재된 Class에 대한 정보들을 저장하는 공간 (클래스의 놀이터)
클래스 로더가 바이트코드를 메모리에 처음으로 Load하는 공간
다음과 같은 정보가 저장
- Type Info : Class / Interface의 타입/이름/부모 정보
- Field Info : 멤버변수의 타입/이름/접근제어자 정보
- Method Info : 메서드의 이름/리턴타입/매개변수/접근제어자 정보
- Constant Pool : 상수 정보
- Class Variable : Static 변수 정보
=> 리플렉션이 가능한 이유
GC (Garbage Collection)
알아서 메모리를 정리해주는 녀석
GC의 대상 기준 : 객체
- Heap에서 더 이상 참조되지 않는 객체
- Stack에서 도달불가능한(Unreachable)객체
GC로 인한 성능상 Issue
Mark & Sweep & Compact 알고리즘
- Mark 단계 : 살아 있는 객체를 식별하여 표시해 놓는 단계
- Sweep 단계 : Heap의 앞 부분부터 확인하여 살아 있는 것만 남긴다.
- Compact 단계 : 각 객체들이 연속되게 쌓이도록 힙의 가장 앞 부분부터 채워서 객체가 존재하는 부분과 객체가 없는 부분으로 나눈다.
GC 실행 = 애플리케이션 일시정지
- GC 실행하는 쓰레드만 작동. 나머지는 모두 정지
stop-the-world를 막을 순 없다. 최소화하는 것이 중요 (GC튜닝의 중요성)
(stop-the-world : GC를 실행하기 위해 JVM이 애플리케이션 실행을 멈추는 것)
대개 GC 튜닝이란, 이 stop-the-world 시간을 줄이는 것이다.
명시적으로 System.gc() 호출
- 시스템의 성능에 매우 큰 영향을 끼치므로 절대 사용하면 안된다.
세대별 GC기법의 적용
(그림 출처 : https://stophyun.tistory.com/37)
(그림 출처 : 코드스쿼드 FINN - 제이브이엠)
알고계신 GC 방식에 대해서 설명해주세요.
Serial GC : 단순하고 전통적인 방식. (Mark & Sweep & Compact) 싱글쓰레드로 성능이 떨어지며 서버용으로 불가
Parallel GC : Serial GC랑 동일하나, Minor GC를 멀티쓰레드로 처리
Parallel Old GC : Parallel GC와 동일하나, Old 영역을 Mark-Summary-Compact로 처리
CMS GC (Concurrent Mark & Sweep GC) : 복잡하나 Low Latency(빠른 응답속도)를 가짐. 메모리와 CPU를 많이 사용하며, Compacting이 기본제공이 아니라 메모리 단편화 심화. 모든 애플리케이션의 응답 속도가 매우 중요할 때 사용
G1 GC (Garbage First) : 가장 빠르다. 일반적인 GC와 다르게 바둑판 영역에 객체할당 및 GC
[참고 : https://d2.naver.com/helloworld/1329]
참고
코드스쿼드 FINN - 제이브이엠 발표자료
'Java' 카테고리의 다른 글
[이펙티브 자바] 아이템 3. private 생성자나 열거 타입으로 싱글턴임을 보증하라 (0) | 2021.05.31 |
---|---|
LinkedList (0) | 2021.05.30 |
[이펙티브 자바] 아이템 2. 생성자에 매개변수가 많다면 빌더를 고려하라 (0) | 2021.05.25 |
[이펙티브 자바] 아이템1. 생성자 대신 정적 팩터리 메서드를 고려하라 (0) | 2021.01.23 |
팩토리 메서드 (2) | 2018.10.17 |
댓글