[Java] 자바 코드 실행 과정과 플랫폼 독립적 특성 이해하기

jina·2024년 12월 5일
0

Java

목록 보기
11/11

자바는 플랫폼 독립성을 가지도록 설계되었다고 표현하는데요. 자바 프로그램이 특정 플랫폼과 무관하게 실행될 수 있는 이유는 Java Virtual Machine(JVM) 덕분입니다. 자바 프로그램은 한 번 컴파일된 후 어떤 운영체제나 하드웨어에서도 실행될 수 있다는 뜻입니다. 이러한 특징 덕분에 현재 웹 어플리케이션 개발에 널리 사용되고 있습니다.

위 내용을 이해하기 위해 자바 코드가 실행되는 과정과 중요 개념을 정리해 보겠습니다.

자바 코드 실행 과정

전체적인 흐름은 다음과 같습니다.

  1. 소스 코드 작성: 자바 소스 코드로 이루어진 .java 파일을 생성합니다.
  2. 컴파일: 자바 컴파일러(javac)가 소스 코드를 바이트코드로 컴파일해서 .class 파일로 저장합니다.
  3. 메모리에 로딩: 프로그램이 실행되면 클래스 로더가 컴파일된 .class 파일을 찾아서 JVM이 사용하는 메모리 공간에 올립니다.
  4. JVM이 프로그램 실행: JVM에 할당된 런타임 데이터 영역에 로드된 바이트코드를 실행 엔진이 (1) 인터프리터로 해석하거나 (2) JIT 컴파일러를 통해 기계어로 변환하여 실행합니다.

이 실행 과정을 이해하는데 필요한 주요 개념들을 정리해 볼게요.

주요 개념 정리

.java 파일과 .class 파일

최초에 작성하는 파일은 .java 확장자가 붙고, 컴파일된 파일은 .class 확장자가 붙습니다.

  • .java 파일
    소스 코드 파일로, 작성한 코드가 저장되어 있습니다. 컴파일 후에도 그대로 유지됩니다.
  • .class 파일
    컴파일 후에 생성되는 실행 파일입니다. JVM이 이해할 수 있는 바이트코드가 저장되어 있습니다. 프로그램이 실행될 때 이 파일이 사용됩니다.

바이트코드(Bytecode)로 컴파일

java 확장자 파일이 포함하고 있는 자바 소스 코드는 자바 컴파일러(javac)에 의해 바이트코드로 컴파일됩니다. 바이트코드는 JVM이 이해할 수 있는 이진 형식의 중간 코드를 말합니다.

(출처: https://www.vincenzoracca.com/en/blog/java/java1)

위 그림은 컴파일된 파일의 바이트코드가 JVM에서 실행된다는 점을 설명하는 그림입니다. 운영체제에서 직접 실행되는 것이 아니라 JVM 위에서 실행되기 때문에 자바 프로그램이 어느 플랫폼에서나 실행될 수 있다는 것을 알 수 있습니다.

핵심 역할을 하는 JVM

한편, JVM은 플랫폼에 종속적입니다. JVM은 바이트코드로 작성된 자바 클래스 파일을 실행할 수 있는 가상 머신인데요. 각 운영체제와 하드웨어에 맞는 JVM이 존재하고, 해당 시스템에 맞는 JVM이 바이트코드를 읽기 때문에 자바 프로그램은 서로 다른 운영체제에서도 실행이 가능한 것입니다.

자바 기반 어플리케이션을 개발하기 위해 설치하는 JDK는 JRE(자바 런타임 환경), 컴파일러(Javac), JVM 등이 포함되어 있어서, JDK를 설치하면 JVM도 손쉽게 함께 설치가 가능합니다.

(출처: https://www.geeksforgeeks.org/jdk-in-java/?ref=ml_lbp)

클래스 정보를 로드하는 클래스 로더

자바 프로그램을 실행하기 위해 JVM이 제공하는 주요 구성 요소를 3가지로 나눌 수 있습니다.

  • 클래스 로더 서브시스템: 클래스 로딩 담당
  • 실행 엔진: 바이트코드 실행
  • 메모리 관리 시스템: JVM 메모리와 GC 관리

이 중 클래스 로더에 대해 좀 더 자세히 알아 볼게요.

JVM 내부에 내장된 클래스 로더는 JVM이 실행되면서 동작합니다. 런타임 시 필요한 클래스를 동적으로 로드해서 JVM 메모리의 메서드 영역(Method Area)에 올리는 역할을 하죠. 컴파일이 완료된 .class 파일을 이 과정을 거쳐 메모리에 올라갑니다. 다만, 자바는 런타임 시점에 특정 클래스가 처음으로 참조됐을 때 해당 클래스를 로드합니다. 아래의 구조를 살펴볼게요.
(출처: https://www.geeksforgeeks.org/jvm-works-jvm-architecture/?ref=lbp)

클래스 로더는 이처럼 계층형으로 설계되어 있습니다. 이런 구조를 사용해서 클래스 로드를 요청받게 되면 클래스 로더 캐시, 상위 클래스 로더, 해당 클래스 로더 순으로 클래스 유무를 먼저 확인한 후 없을 경우 새로 로드해서 메모리에 올립니다.

Application ClassLoader로 클래스 로딩 요청이 들어오면 부모 클래스로 요청이 위임되고, 부모 클래스가 우선 로드를 시도하는 구조입니다. 로딩은 아래 순서로 3단계로 나눠서 진행합니다.

  1. BootStrap ClassLoader: 기본 클래스 및 코어 라이브러리 로드
  2. Extension ClassLoader: 확장 라이브러리 로드
  3. Application ClassLoader: 어플리케이션 클래스 경로에서 로드
  • 클래스 중복 로드 방지: 상위 클래스 로더가 먼저 클래스를 로드할 기회를 가지기 때문에, 이미 로드된 핵심 클래스가 있다면 동일한 이름의 클래스를 로드해서 덮어쓰는 상황을 막을 수 있습니다.
  • 성능 최적화: 캐시 매커니즘을 제공하기 때문에 불필요한 작업을 줄일 수 있습니다.

클래스 로더는 이러한 목적을 가지고 주어진 메모리를 효율적으로 관리합니다. 그렇다면 메모리는 어떤 식으로 구성되어 있을까요?

런타임 데이터 영역의 구성

JVM이 실행되면서 컴퓨터 메모리 일부를 JVM 메모리로 확보하게 됩니다. 이 메모리 영역은 크게 5가지 영역으로 나누어져 있습니다.

  1. 메서드: 공통 데이터를 저장 (예, 클래스 정보)
  2. : 실행 중 생성된 객체를 저장
  3. JVM 스택: 메서드 호출 시 실행 정보 저장 (예, 지역 변수)
  4. PC 레지스터: 실행 중인 JVM 명령어의 위치 저장
  5. 네이티브 메서드 스택(Native Method Stack): 자바 외부 언어로 작성된 코드를 위한 공간 (예, C++)

메서드와 힙은 공유 리소스이며, JVM 스택, PC 레지스터, 네이티브 메서드 스택은 각 스레드마다 생성되어 멀티스레드 환경에서도 독립적인 실행 흐름을 보장합니다. 자바의 멀티스레드 프로그래밍은 이러한 구조가 기반이 되어 가능하다고 할 수 있습니다.


(출처: https://www.geeksforgeeks.org/jvm-works-jvm-architecture/?ref=lbp)

메모리 영역은 이처럼 프로그램을 실행하기 위한 데이터를 저장합니다.

실행 엔진의 두 가지 처리 방식

클래스로더가 메서드 영역에 올린 바이트 코드를 JVM의 구성 요소 중 하나인 실행 엔진이 실행합니다. 바이트 코드를 줄별로 읽고, 다양한 메모리 영역에 있는 데이터와 정보를 사용하고, 명령어를 실행하는 작업을 수행합니다. 주요 작업 메커니즘을 아래처럼 분류할 수 있습니다.

  1. 인터프리터 : 바이트코드를 줄별로 해석해서 실행합니다. 해석 자체는 빠르지만 실행 속도가 느립니다.
  2. JIT 컴파일러(Just-In-Time Compiler) : 바이트 코드를 런타임 중에 네이티브 코드로 변환하는 최적화 프로세스를 담당합니다. 자주 호출되는 메서드의 바이트 코드를 네이티브 코드로 컴파일해 캐싱합니다. 컴파일 속도는 느리지만 실행 속도는 빠르기 때문에 인터프리터의 단점 보완이 가능합니다. (이러한 점 때문에 자바는 컴파일 언어이자 인터프리터 언어라고도 할 수 있습니다.)
  3. 가비지 콜렉터(GC) : 메모리 관리를 위해 참조되지 않은 객체를 힙 영역에서 제거합니다.

정리

  • "Write Once, Run Anywhere" (WORA): 자바는 "한 번 작성하면 어디서든 실행할 수 있다"라는 철학을 가진 프로그래밍 언어입니다.
  • 자바 프로그램은 운영체제에 따라 다르게 동작하지 않고, 각 운영체제에 맞는 JVM 위에서 동작하는 방법을 사용하기 때문에 특정 플랫폼에 종속되지 않게 됩니다.
  • 즉, 자바 프로그램은 한 번 작성하고 컴파일하면 어느 플랫폼에서든 실행할 수 있는 기반을 제공합니다.

자바로 프로그래밍하며 꼭 한 번 정리하고 싶었던 내용인데 좋은 참고 글들을 많이 보며 정리할 수 있게 되어 좋네요! 부족하지만 이 글도 읽는 분들께 조금이나마 도움이 되었으면 좋겠습니다.


참고
https://gyoogle.dev/blog/computer-language/Java/%EC%BB%B4%ED%8C%8C%EC%9D%BC%20%EA%B3%BC%EC%A0%95.html
https://steady-snail.tistory.com/67
https://www.vincenzoracca.com/en/blog/java/java1/
https://www.scaler.com/topics/java/how-java-program-works/
https://www.geeksforgeeks.org/introduction-to-java/
https://d2.naver.com/helloworld/1230

profile
오늘의 기록은 내일의 보물

0개의 댓글