개발/Java live study

[Java] JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가

뚜키 💻 2022. 4. 15. 10:07
반응형

<온라인 자바 라이브 스터디 첫번째 미션>

[Java] JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가

 

✔ 목표

자바 소스 파일(.java)을 JVM으로 실행하는 과정 이해하기

 

✔ 학습할 것

  1. JVM이란 무엇인가
  2. 컴파일하는 방법
  3. 실행하는 방법
  4. 바이트코드란 무엇인가
  5. JIT 컴파일러란 무엇이며 어떻게 동작하는지
  6. JVM 구성 요소
  7. JDK와 JRE의 차이

 


JVM이란 무엇인가

- Java Virtual Machine의 약자로 자바 가상 머신

- 자바 바이트 코드를 실행할 수 있는 주체

- 자바와 운영체제 사이에서 중개자 역할을 수행하여 JVM 덕분에 자바코드로 작성한 프로그램은 운영체제에 독립적으로 실행

- Garbage Collector를 이용한 메모리 관리도 자동적으로 수행

 

자바 프로그램 실행단계

 

 

1. 자바 컴파일러를 이용하여 자바 소스파일을 바이트 코드로 변환

2. 바이트코드를 JVM에서 읽어서 처리

3. 운영체제에서 프로그램 실행

 

 

컴파일하는 방법

  컴파일이란 작성한 프로그램을 실행하기위해 컴퓨터가 이해할 수 있는 기계어로 변환하는 과정

1. 자바 소스 코드 작성 (Test.java)

public class Test {
    public static void main(String[] args) {
        System.out.println("JAVA CODE!!");
    }
}

2. 바이트코드로 변환 (Test.class)

javac Test.java

3. class파일이 생겼는지 확인

 

실행하는 방법

'java 파일명'으로 실행

java Test

 

바이트코드란 무엇인가

- 바이트코드란 JVM이 인식가능한 언어로 자바로 작성된 소스코드를 빌드했을때 만들어짐

- 자바 컴파일러(javac)에 의해 변환되는 .class 파일

- 각 명령어의 크기가 1바이트라서 자바 바이트 코드라고 불림

- JVM에 의해 실행됨

 

 

JIT 컴파일러란 무엇이며 어떻게 동작하는지

- Just-In-Time 컴파일러

 Java 파일이 실행되기위해서 자바 바이트코드는 실시간으로 기계어로 번역되는데 이 역할을 JIT 컴파일러가 수행한다.

인터프리터의 단점을 보완하기 위해 도입된 방식으로 바이트 코드 전체를 컴파일하여 네이티브 코드로 변경하고 이후에는 해당 메서드를 더 이상 인터프리팅하지않고 네이티브 코드로 직접 실행하는 방식. 하나씩 인터프리팅하여 실행하는것이 아니라 바이트 코드 전체가 컴파일된 네이티브 코드를 실행하는 것이라서 인터프리팅 방식보다 실행속도가 빠르다.

 

네이티브 코드는 캐시에 보관되기 때문에 한번 컴파일된 코드는 캐시에서 바로 꺼내서 실행한다. 그렇기때문에 빠르지만 JIT 컴파일러가 컴파일하는 과정은 바이트 코드를 하나씩 인터프리팅하는것보다 더 오래걸리기때문에 JVM은 내부적으로 해당 메서드가 얼마나 자주 호출되고 실행되는지 체크한다. 그리고 일정 기준이 넘을때 컴파일하여 네이티브 코드를 생성한다.

 

 

 

JVM 구성 요소

JVM은 크게 네가지 영역으로 구성되어있다.

 

1. Class Loader

- 클래스 파일들을 Runtime Data Area로 로드하는 역할

- 런타임시 동적으로 클래스를 로드함

 

2. Execution Engine

- Class Loader에 의해 메모리에 적재된 바이트 코드들을 기계어로 변경해 명령어 단위로 실행하는 역할

  * 인터프리터(Interpreter) 방식 : 명령어를 하나하나 실행

  * JIT(Just-In-Time) 컴파일러를 이용한 방식 : 적절한 시간에 전체 바이트 코드를 어셈블러같은 네이티브 코드로 변경해서 Execution Engine이 네이티브로 컴파일된 코드를 실행시키는것으로 성능을 높이는 방식

- 최초의 JVM은 인터프리터 방식이어서 느렸지만 JIT를 사용하여 보완

- JVM은 모든 코드를 JIT 컴파일러 방식으로 실행하지는 않는다. 인터프리터 방식을 사용하다가 일정 기준이 넘어가면 JIT컴파일러방식으로 실행한다

 

3. Garbage Collector

- Heap Memory 영역에 생성된 객체 중 참조되지 않는 객체들을 탐색 후 제거하는 역할

- GC가 실행되는 동안 다른 쓰레드는 일시정지됨

(Full GC가 일어나서 수초간 모든 쓰레드들이 정지한다면 장애로 이어지는 치명적인 문제가 발생할수도있기에 조심해야한다)

 

4. Runtime Data Area

- JVM의 메모리 영역 -> 자바 애플리케이션이 실행될 때 사용되는 데이터들을 적재하는 영역

- 크게 Method Area, Heap Area, Stack Area, PC Register, Native Method Stack으로 나눔

 

4-1. Method 영역 (메서드 영역)

- 모든 Thread가 공유하는 메모리 영역

- 필드 정보 (클래스멤버변수의 이름, 데이터타입, 접근제어자정보 등...)

- 메서드 정보 (메서드 이름, 리턴타입, 파라미터, 접근제어자 등..)

- Type정보 (interface인지 class인지..)

- Constant pool

- static변수

- final class 변수

등등이 생성됨

 

4-2. Heap Area (힙 영역)

- 모든 Thread가 공유하는 메모리 영역

- new 키워드로 생성된 객체와 배열이 생성되는 영역

- 메서드 영역에 로드된 클래스만 생성 가능

- GC가 참조되지 않은 메모리를 확인, 제거하는 영역

 

4-3. Stack Area (스택 영역)

- 메서드 호출시마다 각각의 스택이 생성됨

- 메서드 안에서 사용되는 값들을 저장

- 지역변수, 파라미터, 리턴값, 연산에 사용되는 임시값 등.. 생성

- 메서드 수행이 끝나면 스택 삭제됨

 

4-4. PC Register (PC 레지스터)

- Thread가 시작될때마다 생성

- Thread마다 하나씩 존재

- Program Counter

- Thread가 어떤 부분을 무슨 명령으로 실행해야할지에 대한 기록을 한다

- 현재 수행중인 JVM 명령의 주소를 갖는다

- Thread가 돌아가면서 수행될 수 있도록 한다

 

4-5. Native Method Stack

- 자바 외 언어로 작성된 네이티브 코드를 위한 메모리 영역

- 보통 C/C++등의 코드를 수행하기 위한 스택 (JNI)

 

 

 

JDK와 JRE의 차이

 JDK (Java Development Kit)

- Java 애플리케이션을 만드는데 필요한 도구 등 자바 개발시 필요한 툴킷을 제공하는 도구모음

- JRE + 개발/디버깅 툴

 

 JRE (Java Runtime Environment)

- 컴파일된 자바 프로그램을 실행 시킬 수 있는 환경을 구성해주는 도구

- JVM + Java 패키지 클래스 + 런타임 라이브러리

 

요약하면 JDK는 자바를 개발할때 사용하고 JRE는 자바 파일을 실행하는데 사용

 

 

 

Reference
https://jeong-pro.tistory.com/148
https://steady-coding.tistory.com/305
https://brunch.co.kr/@leejaelin/37
https://velog.io/@ggob_2/java-study-1
https://steady-snail.tistory.com/67

 

반응형