[자바 스터디] 1주차 : JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가.스터디/자바2023. 1. 21. 23:31
Table of Contents
JVM이란 무엇인가
JVM (Java Virtual Machine)
- Java로 작성된 프로그램은
.class
확장자로 컴파일됨- 이렇게 변환된
.class
파일이 JVM 위에서 실행됨 - 즉, JVM은 프로그램을 실행하기 위한 물리적 머신과 유사한 머신을 소프트웨어로 구현한 것을 말함
- 이렇게 변환된
- WORA(Write Once Run Anywhere)
- JVM의 목적 중 하나
- JVM 라는 가상 머신이 OS 위에서 동작하기 때문에 자바 코드가 동일하게 하나의
.class
파일로 컴파일되어도 모든 OS (위의 JVM)에서 실행할 수 있다. - JVM 자체는 OS에 의존적이다.
- [출처 : Tecoble - JVM에 관하여 - Part 1]
JRE (Java Runtime Environment)
- JRE는 자바 코드를 실행하기 위한
환경
을 제공- JRE는
JVM
,클래스 라이브러리
,클래스 로더
로 구성됨
- JRE는
- 클래스 라이브러리
- 필요 시 호출할 수 있는 미리 작성된 코드 컬렉션이 포함됨
- 우리가 자바로 코드를 작성할 때 거의 대부분
import
하여 사용하는java.util.*
등이 여기에 포함
- 클래스 로더
- 런타임에 클래스 라이브러리를 JVM으로 로드함클래스 로더
- 기본적으로 자바 프로그램 실행 시 필요한 클래스 파일을 찾아서 JVM의 메모리에 탑재해주는 역할을 수행
- 구체적으로는
Loading
,Linking
,Initialization
이라는 3가지 역할을 수행함Loading - 필요한 클래스 파일들을 찾아 탑재하는 과정
- 각 클래스 파일이 기본으로 제공되는 클래스 파일(JRE의 라이브러리) 인지, 개발자가 직접 작성한 클래스 파일인지 등에 따라
Class Loader
의 수준이 3가지로 나뉨 - 최하단의
Application Class Loader
로 클래스 파일 탑재 요청이 들어오면, 곧바로 최상단의Bootstrap Class Loader
로 요청을 위임한 뒤, 최상단에서부터 클래스 파일을 찾아서 내려옴. - 상단에서 못찾으면 다시 그 하위에서 찾고, 또 못찾으면 다시 하위로 요청을 내려보내는 방식.
- 각 클래스 파일이 기본으로 제공되는 클래스 파일(JRE의 라이브러리) 인지, 개발자가 직접 작성한 클래스 파일인지 등에 따라
[출처 : Tecoble - JVM에 관하여 - Part 2]
- Bootstrap Class Loader
- 다른 모든 Class Loader의 부모가 되는 ClassLoader
- rt.jar (
Object.class
,String.class
, ...) 등 JVM 구동의 가장 필수적인 라이브러리 클래스를 탑재 - 최상위 Class Loader이므로 다른 Class Loader와는 다르게 Native C 로 작성됨
- Extensions Class Loader
- Bootstrap Class Loader 다음으로 우선순위를 가지는 Class Loader
rt.jar
외의 다른 표준 핵심 라이브러리의 클래스 파일을 JVM에 탑재하는 역할 수행$JAVA_HOME/jre/lib/ext_
에 위치한 클래스 파일을 탑재함
- Application(System) Class Loader
- Classpath(JVM이 클래스를 찾기 위한 기준이 되는 경로, default는
.
)에 있는 클래스들을 탑재함 - 개발자들이 자바 코드로 짠 클래스 파일들을 JVM에 탑재
- Classpath(JVM이 클래스를 찾기 위한 기준이 되는 경로, default는
- 모든 Class Loader에서 클래스 파일을 발견하지 못한 경우,
ClassNotFoundException
을 던짐
근데 자바 9부터 Class Loader에 관련하여 뭔가 많이 바뀐 것 같다.. 나중에 다시 찾아서 정리해야지
Linking
- 로드된 클래스 파일들을 검증하고, 사용할 수 있게 준비하는 과정
Verification
,Preparation
,Resolution
이라는 3가지 단계로 구성됨
- Verification
- 클래스 파일이 유효한지 검증
- Preparation
- 필요한
static field
메모리를 할당,기본 값
으로 초기화 - 이때의
기본 값
은 코드에 작성된초기 값
은 아님,초기 값
의 할당은Initialization
단계에서 수행
- Resolution
Symbolic Reference
값을Direct Reference
라는 JVM의 메모리 주소 값으로 바꿔줌Initialization
- 이 단계에서 클래스 파일의
코드
를 읽어 나감 - 초기 값 할당, 초기화 메서드 실행 등 작업 수행
- 초기화 단계에서
멀티 쓰레드
로 동작하기 때문에 초기화 단계에서도동시성
을 고려해주어야 함
- 초기화 단계에서
- 이 단계까지 완료하면, JVM에서 클래스 파일을
실행
시킬 준비가 완료됨
컴파일 하는 방법
- 자바 코드는
javac
명령으로 컴파일 가능javac <options> <source files>
로 컴파일(.java
->.class
) 가능
javac 옵션
-classpath
- 컴파일 시 참조할 클래스 파일들의 위치인 클래스 패스를 지정할 수 있음
- -d (directory)
- 클래스 파일을 생성할 루트 디렉토리를 지정
- 디렉토리가 없을 경우 오류 발생
- -encoding
- 코드에서 사용할 인코딩 방식을 지정
- -nowarn
- 경고(warning) 메시지를 생성하지 않음
- -verbose
Class Loader
가 로드하는 클래스들의 정보를 출력해줌[parsing started SimpleFileObject[/Users/shhyun/Documents/projects/study/Java8/java8/src/org/example/Main.java]] [parsing completed 11ms] [loading /modules/java.se/module-info.class] [loading /modules/jdk.compiler/module-info.class] [loading /modules/jdk.naming.ldap/module-info.class] [loading /modules/jdk.accessibility/module-info.class] [loading /modules/java.base/module-info.class] [loading /modules/jdk.xml.dom/module-info.class] [loading /modules/jdk.management/module-info.class] [loading /modules/jdk.jshell/module-info.class] [loading /modules/jdk.jstatd/module-info.class] [loading /modules/jdk.hotspot.agent/module-info.class] [loading /modules/java.naming/module-info.class] ...
- -g
- 디버깅 옵션
-g:none
으로 디버깅 정보를 출력하지 않거나,-g:lines, vars, source
를 사용해 각각 코드의 라인, 지역 변수, 소스 파일에 대한 디버깅 정보를 확인할 수 있음- 기본 값은
-g: lines
- -deprecation
- 코드 내에서 사용되어진 deprecated 된 API의 정보를 출력
- -source [자바버전]
- 소스 코드의 버전을 명시. 기본 값은 사용되는
java
의 버전
- 소스 코드의 버전을 명시. 기본 값은 사용되는
- -target [자바버전]
- 지정된 자바 버전에서 호환가능하도록 클래스 파일을 생성
- 상위 버전으로 (옵션 없이) 컴파일된 클래스 파일을 하위 버전에서 실행하면
UnSupportedClassVersionError
오류 발생
실행하는 방법
java
명령어로 컴파일된 자바 바이트 코드(.class
)를 실행할 수 있음
.class
파일을 직접 실행 -java <options> <classfiles> <arguments>
.jar
파일로 실행 -java <options> -jar <jar file path> <arguments>
arguments
는main(String[] args) {}
에서args
로 전달되는 프로그램 실행 시의 인자를 말함- -Xms, -Xmx 옵션
- 프로그램 구동 시 JVM이 사용가능한 메모리 공간을 미리 설정
java -Xms <초기힙크기> -Xmx <최대힙크기> <classfiles> <arguments>
와 같이 사용
바이트코드란 무엇인가
.java
파일을 자바 컴파일러를 통해 컴파일하면.class
파일이 생성되는데,.class
파일의 코드가 바로 자바 바이트 코드- JVM은 자바 바이트 코드를 읽어 실행함
javap
명령을 사용하면.class
파일의 바이트 코드를 보는 것이 가능
- 좌측의 0, 1 과 같은 번호는 코드가 저장된 메모리의 바이트 수를 의미함
aload_0
,invokesspecial #1
과 같은 명령어들은 모두 hex로 변환되어 JVM 메모리에 들어가게 됨
- 지역 변수 등을 저장하는 스택이 있어서 1. 값을 불러와 계산 후 2. 다시 스택에 저장하고 3. 다시 불러와 계산하는 등의 방식으로 프로그램 실행이 이루어짐
JIT 컴파일러란 무엇이며 어떻게 동작하는지
- JIT (Just-In-Time) 컴파일러는 런타임 시 바이트 코드를 OS 시스템 코드로 컴파일 후 저장하여 성능을 개선함
- 한번 컴파일된 메소드는 다시 컴파일하지 않고 저장소에서 불러와 바로 호출
- JIT 컴파일러는 자바 코드를
컴파일
할 때가 아닌JVM
에서 코드를실행
할 때에 관련된 기술임
[출처 : 백기선님 피드백 강의]
- 기본적으로 JVM을 통한 프로그램의 실행은 네이티브 앱에 비해 성능이 떨어질 수 밖에 없음
- JVM이 클래스 파일을 로드하고 바이트 코드의 시맨틱을 판별하며 계산을 수행하는 과정에서의 추가 프로세서 및 메모리 사용 발생
- JIT 컴파일러의 기본 값은
사용
- 다만, 프로그램 시작 시 수천 개의 메소드가 호출되므로 모든 메소드에 대해 JIT 컴파일을 수행하면
결국엔 성능이 좋은 쪽으로 수렴된다고 해도
시작 성능은 크게 저하될 수 있음 - 따라서 JVM은
사전 정의된 임계값
을 두어 특정 메소드가 해당 임계값 이상 호출될 경우 JIT 컴파일을 트리거하여 성능을 개선하는 방식으로 최적화를 하고 있음 - 따라서 자주 사용되는 메소드는 JVM이 시작된 직후 컴파일되며, 자주 사용되지 않는 메소드는 훨씬 나중에(자원에 여유가 있을 때) 컴파일되거나 전혀 컴파일되지 않음
- 다만, 프로그램 시작 시 수천 개의 메소드가 호출되므로 모든 메소드에 대해 JIT 컴파일을 수행하면
JVM 구성 요소
[출처 : 코딩팩토리 - 자바 JVM 내부 구조와 메모리 구조에 대하여]
Runtime Data Area 외부
- 앞에서 살펴본
Class Loader
와Execution Engine
,Garbage Collector
로 구성됨Class Loader - 런타임에
동적으로
프로그램 실행에 필요한 클래스 파일을 불러와Runtime Data Area
에 적재Execution Engine Runtime Data Area
에 적재된 명령어(코드)들을 읽어와실행
Garbage Collector- 더는 사용하지 않는 메모리를 동적으로 회수
Heap
영역에 할당된 객체들 중 더 이상 참조되지 않는 객체를 탐색 & 제거
RunTime Data Area
[출처 : Tecoble - JVM에 관하여 - Part 3]
Method Area
- JVM 당 하나만 생성 (모든 Thread에서 공유)
- 인스턴스 생성을 위한 객체 구조, 생성자, 필드 등이 저장됨
Runtime Constant Pool
,static 변수
,메소드 데이터
와 같은 Class 데이터들도 이곳에서 관리- JVM의 다른 메모리 영역에서 위 정보들에 대한 요청이 오면, 실제 물리 메모리 주소로 변환해서 전달해줌
- (추가) Method Area에 저장되는 정보들
- Type Infomation : 클래스와 인터페이스에 대한 정보
- Runtime Comstant Pool : Type의 상수 정보를 저장하는 Pool. 인덱스를 통해 상수에 접근 가능
- Field Infomation : 인스턴스 변수의 정보를 저장
- Method Information : 메서드의 모든 정보를 저장
- Class Variable : static 키워드로 선언된 변수를 저장
Heap
- JVM 당 하나만 생성 (모든 Thread에서 공유)
- 동시성 문제 발생 가능
- 코드 실행을 위한 Java로 구성된 객체 및 JRE 클래스들이 탑재
String Pool
, 실제 데이터를 가진 인스턴스, 배열 등이 저장됨- Heap 영역이 가득차면
OutOfMemoryError
가 발생
Java Stack
- 각 Thread 별로 할당
- 동시성 문제에서 자유로움
- Heap 메모리 영역보다 비교적 빠른 속도를 보임
- 메소드를 호출할 때마다
Frame
이라는 단위를 Stack에push
함Frame
은 메소드 안의 지역 변수를 가지는Local Variable
, 메소드 내 연산을 위한 바이트 코드 명령문을 가지는Operand Stack
,Constant Pool
참조를 위한Constant Pool Reference
로 구성됨
- Java Stack 영역이 가득차면,
StackOverflowError
가 발생함
Native Method Stacks (C Stacks)
- 각 Thread 별로 할당
- Java 프로그램을 실행하면서, 다른 언어로 작성된 메소드도 실행해야할 때가 있음
- 이 영역은 다른 언어로 작성된 메소드가 호출될 때 해당 메소드에 대한 정보가 쌓이는 영역
PC Registers
- Java에서 Thread는 개별적으로 메소드를 실행함
- 이때, Thread 별로 동시에 실행하는 환경이 보장되어야 하고,
- 따라서, 현재 실행 중인
명령어의 주소값
을 저장할 공간이 필요함
- 만약, 실행한 메소드가 Native인 경우
undefined
가 기록됨- 아닐 경우 명령어의 주소 값이 기록됨
metaspace?
ClassLoader
가 로드한 class들의 metadata가 저장되는 공간- metadata는 JVM이 해당 class에 대해 알아야 하는 모든 정보를 말함
- JVM의
non-heap
공간을 통칭함- 즉,
Method Area
가metaspace
에 포함됨
- 즉,
- 자바 7까지는 Heap의
PermGen
이라는 공간에 metadata가 저장되어 클래스 로드 시-Xmx option
에 의해 설정되는 Heap 크기를 벗어나게 되면OutofMemoryError: PermGen space
와 같은 오류가 발생하기도 했음- 자바 8부터는 이름이
metaspace
로 변경되고,non-heap
공간으로 빠져서 host의 메모리 크기에 의해 크기가 제약됨 - 근데 이는 곧, 자바 애플리케이션으로 인해 metaspace가 넘치게 되면 host 전체가 다운될 수도 있다는 의미기도 함!
- 자바 8부터는 이름이
JDK와 JRE의 차이
[출처 : 백기선님 피드백 강의]
- JDK는 JRE를 포함
- JDK에는 JRE에 없는 개발에 필요한 툴(디버거, 컴파일러 등)을 포함
- JRE만 있어도 (JDK를 사용해) 이미 컴파일된 자바 프로그램을 실행하는데에는 문제가 없음
피드백
- 이미지는 가능하면 직접 그리고, 어려우면 출처는 꼭 표기하기
i. 그림 그리기가 어려우면 컴퓨터로 그리지 말고 (훨씬 어렵고, 본질에서 벗어날 수 있음) 종이에 그려보고 찍어서 올리더라도 직접 그려보라 - 글은 그대로 복사하지 말고, 이해한 후 자신이 이해한대로 다시 적기
Issues
1. 어차피 인터프리팅할 때 기계어로 번역되어야 하는데, 그럼 무조건 JIT를 쓰는게 좋은 것 아닌가? 에 대한 해답
- 기존에는 자바 인터프리터가 한줄한줄 바이트코드를 기계어로 번역하며 프로그램을 실행
- JIT 컴파일러의 등장으로 반복되는 (자주 사용되는) 코드는 기계어로 번역 후 캐싱, 이후에는 캐싱된 기계어를 단순히 가져다가 실행시킴
- 인터프리팅은 한 줄씩 실행할 수 있지만, JIT 컴파일러는 메소드 / 클래스 단위로 수행되어야 하므로 (특히 애플리케이션 시작시점엔) 오버헤드가 클 수 있음
레퍼런스
- https://d2.naver.com/helloworld/1230
- https://www.ibm.com/kr-ko/cloud/learn/jre
- https://tecoble.techcourse.co.kr/tags/jvm/
- https://aws.amazon.com/ko/what-is/java-runtime-environment/
- https://www.redhat.com/ko/topics/cloud-native-apps/what-is-a-Java-runtime-environment
- http://sjava.net/2008/02/javac-%EB%AA%85%EB%A0%B9%EC%96%B4%EC%9D%98-%EC%98%B5%EC%85%98-%EC%A0%95%EB%A6%AC/
- https://www.ibm.com/docs/ko/sdk-java-technology/8?topic=reference-jit-compiler
- https://coding-factory.tistory.com/828
'스터디 > 자바' 카테고리의 다른 글
[자바 스터디] 7주차 : 패키지 (0) | 2023.01.30 |
---|---|
[자바 스터디] 6주차 : 상속 (0) | 2023.01.23 |
[자바 스터디] 5주차 : 클래스 (0) | 2023.01.23 |
[자바 스터디] 3, 4주차 : 연산자, 제어문 (0) | 2023.01.22 |
[자바 스터디] 2주차 : 자바 데이터 타입, 변수 그리고 배열 (0) | 2023.01.22 |
@gmelon :: gmelon's greenhouse
백엔드 개발을 공부하고 있습니다.