시즌 1 자바 기초 스터디
온라인 스터디. Contribute to whiteship/live-study development by creating an account on GitHub.
github.com
- JVM이란 무엇인가
- 컴파일 하는 방법
- 실행하는 방법
- 바이트코드란 무엇인가
- JIT 컴파일러란 무엇이며 어떻게 동작하는지
- JVM 구성 요소
- JDK와 JRE의 차이
JVM이란 무엇인가
Write one run anywhere.
Java의 가장 큰 장점 중 하나는 운영체제에 독립적인 것이다.
예를 들어, C언어는 컴파일 이후 CPU와 OS에 종속적으로 컴파일이 된다.
만약 다른 환경에서 실행을 하고 싶다면 플랫폼에 맞게 코드를 수정해야 한다.
반대로 Java는 어떤 환경에서 컴파일을 해도 동일한 수행을 보장한다.
Java는 CPU, OS에 관계 없이 JVM(Java Virtual Machine)이 이해할 수 있는 바이트 코드로 컴파일을 하기 때문이다.
컴파일 하는 방법
특정 언어로 작성된 소스 코드를 기계가 인식할 수 있는 언어로 변환하는 과정을 컴파일이라 한다.
즉, Java로 작성된 소스 코드를 JVM이 인식할 수 있는 JVM 명령어 코드로 변환하는 과정을 수행하는 것이다.
컴파일 과정을 설명하기 위해 아래 HelloWorld.java 클래스를 작성했다.
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
작성한 클래스를 자바 컴파일러(javac)를 사용해 바이트 코드로 변환하는 작업을 수행한다.
javac HelloWorld.java
실행하는 방법
3단계만 기억하자.
JDK(Java Development Kit)으로 바이트코드를 만들고,
JRE(Java Runtime Environment)로 바이트코드를 실행하면,
JVM(Java Virtual Machine)이 기동된다.
JDK bin 디렉토리에는 javac, java, javap 실행 파일이 존재한다.
javac는 바이트코드 파일을 생성하고, java는 바이트코드를 해석 및 실행을 할 때 사용이 된다.
반대로 바이트코드를 자바 소스코드로 변경하고 싶다면 javap라는 역어셈블러를 사용하면 된다.
바이트코드란 무엇인가
바이트코드는 컴파일 후 생성되는 코드다. 실제로 명령어가 1바이트로 구성이 되어 있어 바이트코드라 부른다.
바이트코드를 생성하는 이유는 JVM이 바이트코드를 인식하고 실행시키기 때문이다.
0: ldc #2 // String "Hello, World!"
2: astore_1
3: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
6: aload_1
7: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
10: return
JIT 컴파일러란 무엇이며 어떻게 동작하는지
Java는 초기 실행 시 인터프리터를 사용해서 바이트코드를 해석한다. 이 때문에 정적 컴파일 언어에 비해 실행 속도가 현저히 느리다.
이러한 문제를 해결하고자 JVM이 반복되어 사용되는 코드나 기계어로 변환 할 때 많은 리소스가 필요한 부분을 감지하여 코드가 실행되는 과정에 실시간으로 변환(Just-In-Time)하여 캐싱하는 방법을 채택했다.
이 때 실시간으로 변환할 때 사용되는 컴파일러가 JIT 컴파일러다.
즉, JIT 컴파일러를 사용하면 이미 한 번 해석한 바이트코드를 다시 읽을 때 또 해석을 하지 않아도 된다.
다만 Java는 JIT 컴파일러만 사용하기에는 CPU와 메모리를 많이 사용하게 되고, 코드 변환에 시간이 걸리기 때문에 처음부터 JIT 컴파일러를 사용하지 않고 인터프리터를 사용해서 바이트코드를 실행시키는 것이다.
JVM 구성요소
클래스 로더
자바 .class 파일을 메모리에 로드하고, 클래스를 초기화시키는 역할이다.
JVM이 시작될 때 3개의 클래스 로더를 사용한다.
- Bootstrap ClassLoader
- java.lang, java.util, java.io와 같은 Java SE의 모든 클래스 파일을 포함하는 rt.jar 파일을 로드한다.
- Extension ClassLoader
- 확장 클래스를 로드한다.
- Bootstrap ClassLoader의 자식 클래스 로더다.
- $JAVA_HOME/jre/lib/ext 디렉토리에 있는 jar 파일을 로드한다.
- System/Application ClassLoader
- 애플리케이션 클래스 경로(CLASSPATH)에서 클래스 파일을 로드한다.
메모리 영역 (JVM Memory)
JVM이 실행 중 사용하는 다양한 메모리 공간을 관리한다.
- Method Area
- 클래스(메타데이터), 필드 정보, 정적 변수 등을 제공한다.
- Heap
- 모든 객체 인스턴스와 배열이 할당되는 공간이다.
- Stack
- 각 스레드마다 생성되며, 메서드 호출과 관련된 지역 변수, 매개변수, 반환 값을 저장한다.
- 스레드마다 생성이 되므로 작업을 마치면 메모리 공간을 반환한다.
- PC(Program Counter) Register
- 현재 실행중인 명령어의 주소를 가리킨다.
- Native Method Stack
- 네이티브 메서드(C, C++로 작성된 메서드)의 호출을 지원한다
실행 엔진 (Execution Engine)
바이트코드를 실제 명령어로 변환하여 실행한다.
이 실행 엔진에 인터프리터, JIT 컴파일러, GC(Garbage Collector)가 포함되어 있다.
네이티브 인터페이스 (Native Method Interface)
네이티브 라이브러리와 상호 작용할 수 있도록 지원해준다.
JNI(Java Native Interface), JNA(Java Native Access)가 포함되어 있다.
사실, 개발하면서 여기까지 건드릴 일은 거의 없다.
네이티브 라이브러리 (Native Method Libraries)
JVM이 네이티브 메서드를 호출할 때 필요한 라이브러리를 제공한다.
JDK와 JRE의 차이
JDK는 자바 애플리케이션을 개발하고 컴파일하기 위한 도구라면,
JRE는 자바 애플리케이션을 실행하기 위한 환경을 제공하는 패키지다.
만약 단순히 자바 프로그램을 실행할 목적만 가졌다면 JRE로도 충분하지만 개발을 하기 위해서는 JDK가 필요하다.
'Java' 카테고리의 다른 글
@Email 어노테이션을 컬렉션 프레임워크에 적용하기 (0) | 2022.10.29 |
---|