본문 바로가기

Java

자바에서 소스 코드가 실행되는 과정

- 이번 글에서는 자바에서 소스코드가 실행되는 과정에 대해서 설명드리겠습니다.

 

1) Hello World

- 자바에서 소스 코드(ex)System.out.println("Hello World"))가 실행되기 위해서는 우선 다음과 같은 코드가 있어야 합니다. 

class Main{
    public static void main(String[] args){
        System.out.println("Hello World");
    }
    
}

- 자바의 클래스는 기본적으로 main 메소드를 갖고 있습니다. 이 main 메소드는 자바 어플리케이션의 시작점입니다. 

  위의 코드에서 Hello World의 출력문은 Main 클래스의 main 메소드 내에 위치하고 있습니다. 

 

2) JVM

- 자바 소스 코드의 동작 과정을 이해하려면 기본적으로 JVM을 알아야 합니다. 

  JVM은 Java Virtual Machine의 줄임말로, 자바 소스 코드를 컴파일해서 생성된

  자바 바이트 코드를 실행하고 해석하는 역할을 합니다. 

  자바에서 JVM을 도입한 이유는 어느 운영체제든 상관없이 JVM만 있으면 자바 코드를 실행 가능하게 하기 위함입니다. 

  이를 다른 말로 이식성(portability)이 높다고 합니다. 

 

※ 이식성이란?

- 컴퓨터 프로그램을 다른 플랫폼에서 실행하는데 필요한 매우 노력이 적은 경우를 이식성이 높다고 합니다. 

 

 

3) 소스 코드의 실행

 

(1) 자바 소스 코드의 컴파일과 로딩 

- 위에서 언급한 것처럼 자바 소스 코드는 자바 컴파일러에 의해서 자바 바이트 코드로 변환됩니다.

   그리고 자바 바이트 코드는 클래스 로더에 의해 JVM으로 로딩되고,

   JVM의 런타임 데이터 영역에 배치됩니다. 

   JVM의 런타임 데이터 영역에 배치되면, 실행 엔진이 이를 해석하고 실행합니다. 

 

※ 클래스 로더란?

- 클래스 로더는 자바 바이트 코드를 동적으로 JVM 내부로 로딩시키는 JRE의 구성요소입니다. 

  클래스 로더는 크게 3가지 타입이 있습니다.

  그것은 부트스트랩 클래스 로더, 확장 클래스 로더, 시스템 클래스 로더입니다. 

  (1) 부트스트랩 클래스 로더

  - 부트 스크랩 클래스 로더는 JVM의 호출에 의해 시작되는 머신 코드입니다. 

    부트 스트랩 클래스 로더의 역할은 첫 번째 자바 클래스 로더를 로딩하는 것입니다.

  (2) 확장 클래스 로더

  - 확장 클래스 로더는 부트 스트랩 클래스 로더의 자식으로서,

     JDK 확장 라이브러리로부터, 코어 자바 클래스들의 확장을 로딩합니다.

  (3) 시스템 클래스 로더

  - 시스템 클래스 로더는 다른 말로 애플리케이션 클래스 로더라고 합니다.

    시스템 클래스 로더는 환경 변수 CLASSPATH에서 발견되는 애플리케이션 클래스들을 로딩합니다. 

    시스템 클래스 로더는 확장 클래스 로더의 자식입니다.  

 

 (2) 자바 런타임 데이터 영역

- 자바 런타임 데이터 영역은 JVM이 프로그램을 수행하기 위해 OS로부터 할당 받은 메모리 공간입니다. 

 

  런타임 데이터 영역은 크게 5가지 영역으로 구성됩니다.

  그것은 메소드 영역, 힙 영역, 스택 영역, PC register, Native Method Stack입니다.  

  (2-1)메소드 영역

  - 메소드 영역은 클래스, 변수, 메소드, static 변수, 상수 정보 등이 저장됩니다.

  (2-2) 힙 영역 

  - 힙 영역은 new 명령어로 생성된 인스턴스와 객체가 저장됩니다. 

    힙 영역은 Garbage Collection 이슈가 일어나는 영역이기도 합니다. 

  (2-3) 스택 영역

  - 스택 영역은 메소드 내에서 사용되는 값들(매개 변수, 지역 변수, 리턴값)이 저장되는 구역입니다. 

  (2-4) PC Register

  - PC Register는 CPU의 PC Register와 비슷하게,  현재 실행중인 JVM 명령의 주소값을 저장합니다. 

  (2-5) Native Method Stack

  - Native Method Stack은 다른 언어(ex)C++)의 메소드 호출을 위해 할당되는 영역입니다.   

 

  위의 5가지 영역 중에서, 메소드 영역과 힙 영역은 모든 스레드가 공유하고, 나머지 영역은 각각의 스레드마다

  할당됩니다. 

 

 (3) 실행 엔진 

- 실행 엔진은 런타임 데이터 영역에 적재된 바이트 코드를 기계어로 변환해 명령어 단위로 실행하는 역할을 맡습니다. 

 

- JVM의 실행 엔진은 크게 2가지로 구성됩니다.

(1) 인터프리터

(2) JIT 컴파일러

  각각에 대해 알아보겠습니다.

 

(1) 인터프리터

- 자바 인터프리터는 자바 바이트 코드를 기계어로 변환하는 역할을 수행합니다.

  인터프리터는 자바 바이트 코드를 한 줄씩 실행하는데, 이 방식은 속도가 느리다는 단점이 있습니다. 

 

(2) JIT 컴파일러

- JIT 컴파일러는 자바 인터프리터의 단점(속도)을 보완하기 위해 적용된 기술입니다.

  JIT 컴파일러는 '자주 사용되는 코드를 런타임에 컴파일하여 재사용' 하는 기술입니다.  

 

 

참고

자바의 신 2권

JVM Performance Optimization

JVM - 실행 엔진(Execution Engine) - Junhyunny’s Devlogs  

JVM Internal (naver.com)

 

   

'Java' 카테고리의 다른 글

리플렉션  (0) 2022.08.17
자바 가비지 컬렉션(1)  (0) 2022.08.11
HashMap vs HashTable vs ConcurrentHashMap  (0) 2022.08.06
자바 스레드(1)  (0) 2022.08.06
CheckedException vs UncheckedException  (0) 2022.08.03