자바 컴파일 과정에 대해

혁콩·2024년 1월 16일
1
post-thumbnail

자바의 특징에 대해 검색하면 항상 나오는 내용이 있다.

"Write once, run anywhere"

직역하자면 "한번 작성하면 어디서나 실행 가능하다" 인데, 이건 곧 운영 체제에 종속되지 않는다는 것이다.

실제로, C언어의 경우 어떤 OS에서 컴파일 했는지에 따라 실행할 수 있는 환경 또한 정해진다. 자바는 과연 어떻게 한번만 작성하면 어디에서나 실행할 수 있는 걸까?

컴파일

우리가 자바 코드를 작성하면 해당 파일은 .java 확장자를 갖는다. 이 자바 파일은 자바 컴파일러(javac)에 의해 바이트 코드 (.class) 파일을 생성한다.
컴파일 과정을 거친 바이트 코드는 JVM에 의해 실행되므로, 운영체제에 종속되지 않을 수 있다.

그렇다면 JVM은 뭘까?

JVM

JVM은 컴파일 된 바이트 코드를 OS가 이해할 수 있는 기계어로 바꾸어 실행하는 역할을 한다. 바꿔 말하면 JVM은 바이트 코드를 실행하는 주체이며, 바이트 코드는 JVM을 거쳐 실행되어야 한다.

JVM은 크게 4가지 요소로 구성된다.

  • Class Loader (클래스 로더)
  • Execution Engine (실행 엔진)
  • Garbage Collector (가비지 콜렉터)
  • Runtime Data Area (런타임 데이터 영역)

이 중 클래스 로더실행 엔진의 동작을 확인해보자.

가비지 콜렉터와 런타임 데이터 영역은 다른 포스트에서 다뤄볼 예정입니다.

Class Loader

클래스 로더는 필요한 클래스를 검색하여 JVM에 적재하는 동작을 한다. 이 클래스 로더는 3개가 존재하며, 몇가지 원칙을 따르며 클래스를 탐색한다.
클래스 로더
클래스 로더의 원칙은 다음과 같다.

  1. 위임 원칙(Delegation principle)
    • 클래스 로딩 요청을 상위 ClassLoader로 전달
    • 상위 클래스가 찾거나 로드할 수 없는 경우에만 클래스 로드
  2. 가시성 원칙(Visibility principle)
    • 하위 클래스 로더는 상위 클래스 로더가 로드한 모든 클래스를 볼 수 있음
    • 상위 클래스 로드는 하위 클래스 로더가 로드한 클래스를 볼 수 없음
  3. 고유성 원리(Uniqueness principle)
    • 중복 클래스가 로드되지 않도록 보장

위 세가지 원칙을 지키며, 클래스 로더는 다음과 같이 동작한다.

  1. JVM이 클래스를 호출
  2. ClassLoader가 정규화된 클래스 이름을 사용, 클래스를 찾아 런타임에 로드를 시도
  3. 클래스가 이미 존재하는 경우, 상위 ClassLoader에게 위임 (가시성 원칙, 위임 원칙)
  4. 마지막 ClassLoader가 클래스를 찾거나 로드할 수 없으면 예외 발생 (ClassNotFoundException / NoClassDefFoundError)

Execution Engine

실행 엔진클래스 로더에 의해 로드된 바이트 코드를 실행한다.

컴퓨터는 바이트 코드를 이해할 수 없다. 때문에, 실행엔진은 이를 운영체제에 맞게끔 바이너리 파일로 변환을 하여 실행한다. 이 과정을 통해 Java의 가장 큰 특징인 "Write Once, Run Anywhere" 를 구현한다.

실행 엔진은 기본적으로 인터프리터 방식으로 동작한다. 한번 컴파일 된 바이트 코드를 라인별로 읽어 바이너리로 변환 후 실행하는데, 이러한 방식을 통해 OS로부터 자유로워 질 수 있었다.

다만, 인터프리터 방식은 속도가 느리다. 느리다는건 곧 어플리케이션의 성능 하락으로 이어진다. Java는 이러한 단점을 보완하기 위해 JIT Compiler를 도입했다.

이 JIT 컴파일러는 자주 사용되는 코드를 런타임에 바이너리로 컴파일함으로써 성능을 향상시킨다.
실행 중 컴파일 임계치(Compile Threshold)를 넘은 코드는 JIT 컴파일러에 의해 컴파일되며, 임계치는 메소드가 호출된 횟수와 메소드가 루프를 빠져나오기 까지의 횟수를 기준으로 정한다.

또한 JIT 컴파일러는 Code Caching 혹은 다양한 최적화 전략을 사용함으로써 높은 성능을 이끌어낸다.

JIT 컴파일러의 동작은 강준현님 블로그를 보고 이해했습니다.
자세한 내용은 IBM - reference-jit-compiler, 특히 how-jit-optimizes-code 에서 볼 수 있습니다.

참고 자료

정프로님 블로그 - JVM 구조와 자바 런타임 메모리 구조
infoworld - All about Java class loaders
Geeksforgeeks - ClassLoader in Java
Turing - # Guide to the Basics of ClassLoader
강준현님 블로그 - JVM 실행 엔진
IBM - reference-jit-compiler

profile
아는 척 하기 좋아하는 콩

0개의 댓글