Java 실행 과정 및 JVM

박영준·2022년 11월 27일
0

Java

목록 보기
5/112

1. Java 실행 과정

자바 클래스 파일 (.java)

  • Java 를 가지고 작성한 자바 소스 코드(.java)를 JVM 이 이해할 수 있는 자바 바이트 코드(.class)로 변환

  • Java 를 설치하면, javac.exe 라는 실행 파일 형태로 설치된다.

자바 컴파일러

  • "Compiler" = "컴퓨터의 명령어 번역 프로그램"

  • '코드 번역기'

2. JVM

1) 정의

  • Java Virtual Machine, 자바 가상 머신

  • '자바 프로그램 실행 환경'을 만들어 주는 소프트웨어

    • '자바 프로그램을 실행시킬 수 있는 가상의 기기'를 만들어주는 것
      • 따라서, 어느 장비에서든 JVM 을 깔아주면 Java 프로그램이 작동 가능해진다.
  • 자바 실행 환경(JRE, Java Runtime Environment)에 포함되어 있음
    → 현재 사용하는 컴퓨터의 운영 체제에 맞는 JRE 가 설치되어 있다면, JVM 이 설치되어 있다는 뜻

  • 자바 코드를 컴파일하여 .class 바이트 코드로 만들면, 이 코드가 자바 가상 머신 환경에서 실행됨

  • Java 언어로 작성된 Test.java 를 컴파일하면, Test.class 파일이 생성됨
    → JVM 은 이 바이트 코드를 각각의 플랫폼에 설치되어 있는 운영 체제에 맞는 실행 파일로 바꿔준다.

  • 하나의 바이트 코드(.class)로, JVM이 설치되어 있는 모든 플랫폼에서 동작 가능
    → 각각의 플랫폼에 맞게끔 컴파일을 따로따로 해줘야 할 필요 X
    → 플랫폼에 영향을 받지 X
    → JVM 을 사용하는 Java 어플리케이션은 JVM 하고만 상호작용을 하므로, OS가 달라지더라도 프로그램의 변경 없이 실행이 가능

  • 실행 엔진(Execution Engine)은 바이트 코드를 JVM 내부에서 기계가 실행할 수 있는 형태로 변경하는데
    이때 인터프리터, JIT 컴파일러를 사용한다.

    실행 엔진 (Execution Engine)

    • 클래스 로더를 통해, 런타임 데이터 영역에 배치된 바이트 코드들를 명령어 단위로 읽어서 실행

2) 구성

(1) 자바 바이트 코드 (.class)

① 정의

  • Java bytecode
    → 자바 컴파일러에 의해 변환되는 코드의 명령어 크기가 '1바이트'이므로, 자바 바이트 코드라고 불린다.

  • 운영체제가 읽을 수 있도록 Java 컴파일러가 변환한 코드

  • 자바 컴파일러에 의해, JVM 이 이해할 수 있는 언어로 변환된 자바 소스 코드

    • 컴파일러 : java -> class 로 변환해준다.
      • 운영체제는 java를 읽을 수 없기 때문
      • 자바 바이트 코드의 확장자는 .class
  • JVM 만 설치되어 있으면, 어떤 운영 체제에서라도 실행 가능

② 컴파일 과정

  1. 자바 컴파일러를 통해, 자바 소스 코드(.java)가 전달

  2. 이 코드를 Bytecode 로 인코딩한다.

  3. 소스 코드를 Bytecode 로 변환하는 동안 컴파일러는 다음 단계를 따른다.
    1) Parse : .java 소스 파일을 읽은 후, 결과 토큰을 AST(Abastract Syntax Tree) 노드에 매핑

    2) Enter : 정의된 심볼들을 심볼테이블(Symbol table) 에 저장

    3) Process annotations : 요청된 경우, 지정된 컴파일 위치에서 찾은 애너테이션을 처리

    4) Attribute : 구문 트리에 속성 부여 (이름 확인, 유형 검사 및 상수 정의)

    5) Flow : 이전 단계의 트리에 대한 데이터 흐름을 분석 (할당 및 도달 가능성에 대한 검사)

    6) Desugar : AST를 다시 작성하고, 몇몇 syntactic sugar들을 번역

    7) Generate : .class 파일을 생성

  4. Terminal에서 컴파일
    1) 작성한 코드가 있는 위치로 이동해 javac 파일명.java 명령어를 작성

    2) .class파일 생성 확인

(2) 자바 인터프리터

  • 운영체제가 읽은 바이트 코드 -> 기계가 실행 가능한 기계어로 번역

  • 바이트 코드 명령어를 하나씩 읽어서, 네이티브 코드로 변환하고 실행

  • 해석은 빠르나, 실행 시간이 길고 느리다

(3) JIT 컴파일러

① 정의

  • Just-In-Time 컴파일러

  • 인터프리터의 단점(느린 실행 시간)을 보완하기 위해 도입
    → 인터프리터 방식으로 실행하다가, 적절한 시점에 바이트 코드 전체를 네이티브 코드로 바꾼다.
    → 그 다음부터 인터프리터는 네이티브 코드로 컴파일된 코드를 바로 사용한다.
    → 즉, 자바 인터프리터의 효율을 높여주는 것!

  • 장점

    • 하나씩 인터프리팅 하는 것보다 네이티브 코드를 실행하는 것이 빠르다.
    • 네이티브 코드를 캐시에 보관하기 때문에, 한 번 컴파일된 코드는 계속 빠르게 수행된다.

② 컴파일

메소드의 수행 빈도 多 경우, 인터프리터 로 컴파일 하는 것이 유리 (한 번만 실행되는 코드 등...)

메소드의 수행 빈도 小 경우, JIT 컴파일러로 컴파일 하는 것이 유리

③ 동작 형태

바이트 코드를 IR(Intermediate Representation, 중간 단계의 표현)로 변환하여 최적화를 수행하고
그 다음 네이티브 코드를 생성

Intermediate Representation

  • 소스 코드를 표현하기 위해 컴파일러 or 가상 시스템에서 내부적으로 사용하는 데이터 구조 or 코드
  • 최적화, 번역 등... 추가 처리를 위해 도움이 되도록 설계되었다.

(4) 메모리 영역

  • Java 데이터를 저장하는 영역

  • 운영체제로부터 JVM이 할당받은 메모리 영역

(5) 클래스 로더 (loader)

① 정의

  • Java.class 바이트 코드 -> 메모리 영역에 담는 운반기

    • 컴파일 된 바이트 코드는 클래스 로더에 전달된다.
    • JVM으로 class(바이트 코드)를 불러와서 메로리에 저장
  • 런타임 中 자바 클래스들을 동적으로 JVM 에 로딩하는 역할
    → 실행 中 필요한 클래스 파일을 메모리에 올리는 역할
    → Java 클래스는 한번에 메모리에 올라가지 않고, 클래스 로더에 의해 어플리케이션에서 필요 할 때만 메모리에 올라가게 된다.

  • 클래스 로더 덕분에,
    JVM 은 Java 프로그램 실행 中 어떤 파일이 있어야 하는지 알지 않아도 된다.

② 특징

  1. 계층 구조
    클래스 로더끼리 부모-자식 관계를 이뤄 계층 구조로 생성된다.
    → 최상위 클래스 로더는 부트스트랩 클래스 로더(Bootstrap Class Loader)

  2. 위임 모델

    • 계층 구조를 바탕으로, 클래스 로더끼리 로드를 위임하는 구조로 동작한다.

    • 클래스를 로드할 때, 먼저 상위 클래스 로더를 확인하여

      • 상위 클래스 로더에 있다면, 해당 클래스를 사용
      • 없다면, 로드를 요청받은 클래스 로더가 클래스를 로드
  3. 가시성(visiblility) 제한
    하위 클래스 로더는 상위 클래스 로더를 찾을 수 O,
    상위 클래스 로더는 하위 클래스로더의 클래스를 찾을 수 X

  4. 언로드(unload) 불가
    클래스 로더는 클래스를 로드할 수 O, 언로드할 수는 X

    그 대신, 현재 클래스 로더를 새로 삭제하고 아예 새로운 클래스 로더를 생성하는 방법을 사용할 수 있다.

(6) 가비지 컬렉터 (Garbage Collector)

  • Heap 영역에 참조되지 않은 객체를 제거 하는 역할

  • 더는 사용하지 않는 메모리를 자동으로 회수

  • 개발자가 따로 메모리를 관리하지 않아도 되므로, 더욱 손쉽게 프로그래밍을 할 수 있도록 도와줍니다.

3) 변환 이유

JVM 으로 자바 바이트 코드(.class 파일)를 OS에 특화된 코드로 변환하여 실행한다.
그 이유는?

  • 일반 어플리케이션의 코드

    • 어플리케이션 → OS → 하드웨어 로 전달
    • 하드웨어에 맞게 완전히 컴파일 된 상태 X
      → 따라서, 실행 시에 해석되므로, 속도가 느리다
    • (JVM이 없을 경우) 일반어플리케이션은 OS와 바로 맞붙어 있기 때문에, OS에 종속적이게 된다.
  • Java 어플리케이션

    • Java 어플리케이션 → JVM → OS → 하드웨어 로 거침
    • JVM 과만 상호작용하므로, OS 와 하드웨어에 독립적이여서 다른 OS에서도 프로그램의 변경 없이도 실행 가능한 것
      • 예시 : JVM(Window용), JVM(Macintosh용), JVM(Linux용) ...
      • 단, JVM 은 OS에 종속적이므로, 해당 OS에서 실행 가능한 JVM이 필요

4) JRE

  • Java Runtime Environment, 자바 실행 환경

  • JVM 을 설치하기 위해서는 JRE를 설치해야 한다.

    • 그러나 JRE(JVM) 만으로는 Java 프로그램을 실행시키는 것까지만 할 수 있다.
      • JRE 는 .class 파일만 실행 가능
      • JDK 가 javac 명령을 통해 .java 파일을 실행가능한 .class 파일로 변환

5) JDK

  • Java Development Kit, 자바 개발 키트

  • 컴파일러 역할

    • JDK는 .java 파일들을 .class 파일들로 변환해주는 Java Compiler(javac) 기능이 있다.
  • JRE(JVM)의 기능을 포함하고 있다.

  • 디버깅하는 jdb 등...의 기능이 있다.

    참고: 디버깅

6) main 메소드

  • JVM 은 가장 먼저 해당 클래스의 main 메소드를 실행시킨다.

    public class Main {
        public static void main(String[] args) {
            System.out.println("Hello world!");
        }
    }
  • main 클래스의 이름은 .java 의 이름과 동일해야 한다.


용어

  • javac: .java 파일을 .class 파일로 컴파일 해주는 컴파일러
  • java: javac로 컴파일 된 class 파일을 실행하는 프로그램

참고: 자바 프로그래밍
참고: Java ClassLoader 알아보기
참고: [1주차] JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가.
참고: Java(자바) 코드를 실행하면 벌어지는 일
참고: [Java] 자바코드가 실행되는 과정에 대해 알아보자

profile
개발자로 거듭나기!

0개의 댓글